<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<meta name="theme-color" content="#222" media="(prefers-color-scheme: light)">
<meta name="theme-color" content="#222" media="(prefers-color-scheme: dark)"><meta name="generator" content="Hexo 5.2.0">


  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">



<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.2/css/all.min.css" integrity="sha256-xejo6yLi6vGtAjcMIsY8BHdKsLg7QynVlFMzdQgUuy8=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.1.1/animate.min.css" integrity="sha256-PR7ttpcvz8qrF57fur/yAx1qXMFJeJFiA6pSzWi0OIE=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fancybox/3.5.7/jquery.fancybox.min.css" integrity="sha256-Vzbj7sDDS/woiFS3uNKo8eIuni59rjyNGtXfstRzStA=" crossorigin="anonymous">

<script class="next-config" data-name="main" type="application/json">{"hostname":"gz1234.gitee.io","root":"/","images":"/images","scheme":"Gemini","darkmode":true,"version":"8.12.3","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12},"copycode":{"enable":true,"style":"flat"},"bookmark":{"enable":true,"color":"#222","save":"auto"},"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"stickytabs":false,"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"fadeInDown","post_body":"fadeInDown","coll_header":"fadeInLeft","sidebar":"fadeInUp"}},"prism":false,"i18n":{"placeholder":"搜索...","empty":"没有找到任何搜索结果：${query}","hits_time":"找到 ${hits} 个搜索结果（用时 ${time} 毫秒）","hits":"找到 ${hits} 个搜索结果"},"path":"/search.xml","localsearch":{"enable":true,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false}}</script><script src="/js/config.js"></script>

    <meta name="description" content="谈一下你对MVVM原理的理解   传统的MVC指的是,用户操作会请求服务端路由，路由会调用对应的控制器来处理,控制器会获取数据。将结果返回给前端,页面重新渲染 MVVM:传统的前端会将数据手动渲染到页面上,MVVM模式不需要用户收到操作dom元素,将数据绑定到viewModel层上，会自动将数据渲染到页面中，视图变化会通知viewModel层更新数据。ViewModel就是我们MVVM模式中的桥梁">
<meta property="og:type" content="article">
<meta property="og:title" content="vue2代码简单解析">
<meta property="og:url" content="https://gz1234.gitee.io/2020/10/21/vue%E7%AC%94%E8%AE%B0/vue-souce/index.html">
<meta property="og:site_name" content="郭泽">
<meta property="og:description" content="谈一下你对MVVM原理的理解   传统的MVC指的是,用户操作会请求服务端路由，路由会调用对应的控制器来处理,控制器会获取数据。将结果返回给前端,页面重新渲染 MVVM:传统的前端会将数据手动渲染到页面上,MVVM模式不需要用户收到操作dom元素,将数据绑定到viewModel层上，会自动将数据渲染到页面中，视图变化会通知viewModel层更新数据。ViewModel就是我们MVVM模式中的桥梁">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://gz1234.gitee.io/2020/10/21/vue%E7%AC%94%E8%AE%B0/vue-souce/MVVM.jpg">
<meta property="og:image" content="https://gz1234.gitee.io/2020/10/21/vue%E7%AC%94%E8%AE%B0/vue-souce/%E5%93%8D%E5%BA%94%E5%BC%8F%E6%95%B0%E6%8D%AE%E5%8E%9F%E7%90%86.png">
<meta property="og:image" content="https://gz1234.gitee.io/2020/10/21/vue%E7%AC%94%E8%AE%B0/vue-souce/%E6%95%B0%E7%BB%84%E5%93%8D%E5%BA%94%E5%BC%8F%E6%95%B0%E6%8D%AE%E5%8E%9F%E7%90%86.png">
<meta property="og:image" content="https://gz1234.gitee.io/2020/10/21/vue%E7%AC%94%E8%AE%B0/vue-souce/%E4%B8%BA%E4%BD%95%E5%BC%82%E6%AD%A5%E6%B8%B2%E6%9F%93.png">
<meta property="og:image" content="https://gz1234.gitee.io/2020/10/21/vue%E7%AC%94%E8%AE%B0/vue-souce/nextTick%E5%8E%9F%E7%90%86%E5%89%96%E6%9E%90.png">
<meta property="og:image" content="https://gz1234.gitee.io/2020/10/21/vue%E7%AC%94%E8%AE%B0/vue-souce/%E8%AE%A1%E7%AE%97%E5%B1%9E%E6%80%A7.png">
<meta property="og:image" content="https://gz1234.gitee.io/2020/10/21/vue%E7%AC%94%E8%AE%B0/vue-souce/lifecycle.png">
<meta property="og:image" content="https://gz1234.gitee.io/2020/10/21/vue%E7%AC%94%E8%AE%B0/vue-souce/%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F.png">
<meta property="og:image" content="https://gz1234.gitee.io/2020/10/21/vue%E7%AC%94%E8%AE%B0/vue-souce/vue-diff.jpg">
<meta property="og:image" content="https://gz1234.gitee.io/2020/10/21/vue%E7%AC%94%E8%AE%B0/vue-souce/diff-key.jpg">
<meta property="og:image" content="https://gz1234.gitee.io/2020/10/21/vue%E7%AC%94%E8%AE%B0/vue-souce/%E7%BB%84%E4%BB%B6%E6%B8%B2%E6%9F%93%E6%B5%81%E7%A8%8B.png">
<meta property="og:image" content="https://gz1234.gitee.io/2020/10/21/vue%E7%AC%94%E8%AE%B0/vue-souce/%E4%BA%8B%E4%BB%B6%E5%88%9D%E5%A7%8B%E5%8C%96.png">
<meta property="og:image" content="https://gz1234.gitee.io/2020/10/21/vue%E7%AC%94%E8%AE%B0/vue-souce/%E7%BB%84%E4%BB%B6%E7%9A%84%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F-1582263422513.png">
<meta property="og:image" content="https://gz1234.gitee.io/2020/10/21/vue%E7%AC%94%E8%AE%B0/vue-souce/%E6%8F%92%E6%A7%BD.png">
<meta property="og:image" content="https://vuex.vuejs.org/vuex.png">
<meta property="article:published_time" content="2020-10-21T02:07:09.000Z">
<meta property="article:modified_time" content="2023-04-27T01:11:48.105Z">
<meta property="article:author" content="郭泽">
<meta property="article:tag" content="vue">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://gz1234.gitee.io/2020/10/21/vue%E7%AC%94%E8%AE%B0/vue-souce/MVVM.jpg">


<link rel="canonical" href="https://gz1234.gitee.io/2020/10/21/vue%E7%AC%94%E8%AE%B0/vue-souce/">



<script class="next-config" data-name="page" type="application/json">{"sidebar":"","isHome":false,"isPost":true,"lang":"zh-CN","comments":true,"permalink":"https://gz1234.gitee.io/2020/10/21/vue%E7%AC%94%E8%AE%B0/vue-souce/","path":"2020/10/21/vue笔记/vue-souce/","title":"vue2代码简单解析"}</script>

<script class="next-config" data-name="calendar" type="application/json">""</script>
<title>vue2代码简单解析 | 郭泽</title>
  





  <noscript>
    <link rel="stylesheet" href="/css/noscript.css">
  </noscript>
</head>

<body itemscope itemtype="http://schema.org/WebPage" class="use-motion">
  <div class="headband"></div>

  <main class="main">
    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏" role="button">
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <i class="logo-line"></i>
      <p class="site-title">郭泽</p>
      <i class="logo-line"></i>
    </a>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>



<nav class="site-nav">
  <ul class="main-menu menu"><li class="menu-item menu-item-home"><a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a></li><li class="menu-item menu-item-about"><a href="/about/" rel="section"><i class="fa fa-user fa-fw"></i>关于</a></li><li class="menu-item menu-item-tags"><a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a></li><li class="menu-item menu-item-categories"><a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a></li><li class="menu-item menu-item-archives"><a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a></li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup"><div class="search-header">
  <span class="search-icon">
    <i class="fa fa-search"></i>
  </span>
  <div class="search-input-container">
    <input autocomplete="off" autocapitalize="off" maxlength="80"
           placeholder="搜索..." spellcheck="false"
           type="search" class="search-input">
  </div>
  <span class="popup-btn-close" role="button">
    <i class="fa fa-times-circle"></i>
  </span>
</div>
<div class="search-result-container no-result">
  <div class="search-result-icon">
    <i class="fa fa-spinner fa-pulse fa-5x"></i>
  </div>
</div>

    </div>
  </div>

</div>
        
  
  <div class="toggle sidebar-toggle" role="button">
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
  </div>

  <aside class="sidebar">

    <div class="sidebar-inner sidebar-nav-active sidebar-toc-active">
      <ul class="sidebar-nav">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <div class="sidebar-panel-container">
        <!--noindex-->
        <div class="post-toc-wrap sidebar-panel">
            <div class="post-toc animated"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E8%B0%88%E4%B8%80%E4%B8%8B%E4%BD%A0%E5%AF%B9MVVM%E5%8E%9F%E7%90%86%E7%9A%84%E7%90%86%E8%A7%A3"><span class="nav-number">1.</span> <span class="nav-text">谈一下你对MVVM原理的理解</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E8%AF%B7%E8%AF%B4%E4%B8%80%E4%B8%8B%E5%93%8D%E5%BA%94%E5%BC%8F%E6%95%B0%E6%8D%AE%E7%9A%84%E5%8E%9F%E7%90%86%EF%BC%9F"><span class="nav-number">2.</span> <span class="nav-text">请说一下响应式数据的原理？</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%90%86%E8%A7%A3"><span class="nav-number">2.1.</span> <span class="nav-text">理解</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8E%9F%E7%90%86"><span class="nav-number">2.2.</span> <span class="nav-text">原理</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Vue%E4%B8%AD%E6%98%AF%E5%A6%82%E4%BD%95%E6%A3%80%E6%B5%8B%E6%95%B0%E7%BB%84%E5%8F%98%E5%8C%96"><span class="nav-number">3.</span> <span class="nav-text">Vue中是如何检测数组变化?</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%90%86%E8%A7%A3-1"><span class="nav-number">3.1.</span> <span class="nav-text">理解</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8E%9F%E7%90%86-1"><span class="nav-number">3.2.</span> <span class="nav-text">原理</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E4%B8%BA%E4%BD%95Vue%E9%87%87%E7%94%A8%E5%BC%82%E6%AD%A5%E6%B8%B2%E6%9F%93"><span class="nav-number">4.</span> <span class="nav-text">为何Vue采用异步渲染?</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%90%86%E8%A7%A3-2"><span class="nav-number">4.1.</span> <span class="nav-text">理解</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8E%9F%E7%90%86-2"><span class="nav-number">4.2.</span> <span class="nav-text">原理</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#nextTick%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86"><span class="nav-number">5.</span> <span class="nav-text">nextTick实现原理?</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%90%86%E8%A7%A3-%E5%AE%8F%E4%BB%BB%E5%8A%A1%E5%92%8C%E5%BE%AE%E4%BB%BB%E5%8A%A1-%E5%BC%82%E6%AD%A5%E6%96%B9%E6%B3%95"><span class="nav-number">5.1.</span> <span class="nav-text">理解:(宏任务和微任务) 异步方法</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8E%9F%E7%90%86-3"><span class="nav-number">5.2.</span> <span class="nav-text">原理</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Vue%E4%B8%ADComputed%E7%9A%84%E7%89%B9%E7%82%B9"><span class="nav-number">6.</span> <span class="nav-text">Vue中Computed的特点</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%90%86%E8%A7%A3-3"><span class="nav-number">6.1.</span> <span class="nav-text">理解</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8E%9F%E7%90%86-4"><span class="nav-number">6.2.</span> <span class="nav-text">原理</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Watch%E4%B8%AD%E7%9A%84deep-true-%E6%98%AF%E5%A6%82%E4%BD%95%E5%AE%9E%E7%8E%B0%E7%9A%84"><span class="nav-number">7.</span> <span class="nav-text">Watch中的deep:true 是如何实现的</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%90%86%E8%A7%A3-4"><span class="nav-number">7.1.</span> <span class="nav-text">理解</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8E%9F%E7%90%86-5"><span class="nav-number">7.2.</span> <span class="nav-text">原理</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Vue%E7%BB%84%E4%BB%B6%E7%9A%84%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F"><span class="nav-number">8.</span> <span class="nav-text">Vue组件的生命周期</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%90%86%E8%A7%A3-5"><span class="nav-number">8.1.</span> <span class="nav-text">理解</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#%E8%A6%81%E6%8E%8C%E6%8F%A1%E6%AF%8F%E4%B8%AA%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E4%BB%80%E4%B9%88%E6%97%B6%E5%80%99%E8%A2%AB%E8%B0%83%E7%94%A8"><span class="nav-number">8.1.1.</span> <span class="nav-text">要掌握每个生命周期什么时候被调用</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%E8%A6%81%E6%8E%8C%E6%8F%A1%E6%AF%8F%E4%B8%AA%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E5%86%85%E9%83%A8%E5%8F%AF%E4%BB%A5%E5%81%9A%E4%BB%80%E4%B9%88%E4%BA%8B"><span class="nav-number">8.1.2.</span> <span class="nav-text">要掌握每个生命周期内部可以做什么事</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8E%9F%E7%90%86-6"><span class="nav-number">8.2.</span> <span class="nav-text">原理</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#ajax%E8%AF%B7%E6%B1%82%E6%94%BE%E5%9C%A8%E5%93%AA%E4%B8%AA%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E4%B8%AD"><span class="nav-number">9.</span> <span class="nav-text">ajax请求放在哪个生命周期中</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%90%86%E8%A7%A3-6"><span class="nav-number">9.1.</span> <span class="nav-text">理解</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E4%BD%95%E6%97%B6%E9%9C%80%E8%A6%81%E4%BD%BF%E7%94%A8beforeDestroy"><span class="nav-number">10.</span> <span class="nav-text">何时需要使用beforeDestroy</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%90%86%E8%A7%A3-7"><span class="nav-number">10.1.</span> <span class="nav-text">理解</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Vue%E4%B8%AD%E6%A8%A1%E6%9D%BF%E7%BC%96%E8%AF%91%E5%8E%9F%E7%90%86"><span class="nav-number">11.</span> <span class="nav-text">Vue中模板编译原理</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Vue%E4%B8%ADv-if%E5%92%8Cv-show%E7%9A%84%E5%8C%BA%E5%88%AB"><span class="nav-number">12.</span> <span class="nav-text">Vue中v-if和v-show的区别</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%90%86%E8%A7%A3-8"><span class="nav-number">12.1.</span> <span class="nav-text">理解</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8E%9F%E7%90%86-7"><span class="nav-number">12.2.</span> <span class="nav-text">原理</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E4%B8%BA%E4%BB%80%E4%B9%88V-for%E5%92%8Cv-if%E4%B8%8D%E8%83%BD%E8%BF%9E%E7%94%A8"><span class="nav-number">13.</span> <span class="nav-text">为什么V-for和v-if不能连用</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%90%86%E8%A7%A3-9"><span class="nav-number">13.1.</span> <span class="nav-text">理解</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%94%A8vnode%E6%9D%A5%E6%8F%8F%E8%BF%B0%E4%B8%80%E4%B8%AADOM%E7%BB%93%E6%9E%84"><span class="nav-number">14.</span> <span class="nav-text">用vnode来描述一个DOM结构</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#diff%E7%AE%97%E6%B3%95%E7%9A%84%E6%97%B6%E9%97%B4%E5%A4%8D%E6%9D%82%E5%BA%A6"><span class="nav-number">15.</span> <span class="nav-text">diff算法的时间复杂度</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%AE%80%E8%BF%B0Vue%E4%B8%ADdiff%E7%AE%97%E6%B3%95%E5%8E%9F%E7%90%86"><span class="nav-number">16.</span> <span class="nav-text">简述Vue中diff算法原理</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%90%86%E8%A7%A3-10"><span class="nav-number">16.1.</span> <span class="nav-text">理解</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8E%9F%E7%90%86-8"><span class="nav-number">16.2.</span> <span class="nav-text">原理</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#v-for%E4%B8%AD%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E7%94%A8key-%E5%9B%BE%E8%A7%A3"><span class="nav-number">17.</span> <span class="nav-text">v-for中为什么要用key (图解)</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%8F%8F%E8%BF%B0%E7%BB%84%E4%BB%B6%E6%B8%B2%E6%9F%93%E5%92%8C%E6%9B%B4%E6%96%B0%E8%BF%87%E7%A8%8B"><span class="nav-number">18.</span> <span class="nav-text">描述组件渲染和更新过程</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%90%86%E8%A7%A3-11"><span class="nav-number">18.1.</span> <span class="nav-text">理解</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%BB%84%E4%BB%B6%E4%B8%AD%E7%9A%84-data%E4%B8%BA%E4%BB%80%E4%B9%88%E6%98%AF%E4%B8%80%E4%B8%AA%E5%87%BD%E6%95%B0"><span class="nav-number">19.</span> <span class="nav-text">组件中的 data为什么是一个函数?</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%90%86%E8%A7%A3-12"><span class="nav-number">19.1.</span> <span class="nav-text">理解</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8E%9F%E7%90%86-9"><span class="nav-number">19.2.</span> <span class="nav-text">原理</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Vue%E4%B8%AD%E4%BA%8B%E4%BB%B6%E7%BB%91%E5%AE%9A%E7%9A%84%E5%8E%9F%E7%90%86"><span class="nav-number">20.</span> <span class="nav-text">Vue中事件绑定的原理</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%90%86%E8%A7%A3-13"><span class="nav-number">20.1.</span> <span class="nav-text">理解</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8E%9F%E7%90%86-10"><span class="nav-number">20.2.</span> <span class="nav-text">原理</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#%E5%8E%9F%E7%94%9Fdom%E7%9A%84%E7%BB%91%E5%AE%9A"><span class="nav-number">20.2.1.</span> <span class="nav-text">原生dom的绑定</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#v-model%E4%B8%AD%E7%9A%84%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86%E5%8F%8A%E5%A6%82%E4%BD%95%E8%87%AA%E5%AE%9A%E4%B9%89v-model"><span class="nav-number">21.</span> <span class="nav-text">v-model中的实现原理及如何自定义v-model</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%90%86%E8%A7%A3-14"><span class="nav-number">21.1.</span> <span class="nav-text">理解</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8E%9F%E7%90%86-11"><span class="nav-number">21.2.</span> <span class="nav-text">原理</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Vue%E4%B8%ADv-html%E4%BC%9A%E5%AF%BC%E8%87%B4%E5%93%AA%E4%BA%9B%E9%97%AE%E9%A2%98"><span class="nav-number">22.</span> <span class="nav-text">Vue中v-html会导致哪些问题?</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%90%86%E8%A7%A3-15"><span class="nav-number">22.1.</span> <span class="nav-text">理解</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8E%9F%E7%90%86-12"><span class="nav-number">22.2.</span> <span class="nav-text">原理</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Vue%E7%88%B6%E5%AD%90%E7%BB%84%E4%BB%B6%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E8%B0%83%E7%94%A8%E9%A1%BA%E5%BA%8F"><span class="nav-number">23.</span> <span class="nav-text">Vue父子组件生命周期调用顺序</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%90%86%E8%A7%A3-16"><span class="nav-number">23.1.</span> <span class="nav-text">理解</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8E%9F%E7%90%86-13"><span class="nav-number">23.2.</span> <span class="nav-text">原理</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Vue%E7%BB%84%E4%BB%B6%E5%A6%82%E4%BD%95%E9%80%9A%E4%BF%A1"><span class="nav-number">24.</span> <span class="nav-text">Vue组件如何通信?</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Vue%E4%B8%AD%E7%9B%B8%E5%90%8C%E9%80%BB%E8%BE%91%E5%A6%82%E4%BD%95%E6%8A%BD%E7%A6%BB%EF%BC%9F"><span class="nav-number">25.</span> <span class="nav-text">Vue中相同逻辑如何抽离？</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E4%BD%BF%E7%94%A8%E5%BC%82%E6%AD%A5%E7%BB%84%E4%BB%B6%EF%BC%9F"><span class="nav-number">26.</span> <span class="nav-text">为什么要使用异步组件？</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%90%86%E8%A7%A3-17"><span class="nav-number">26.1.</span> <span class="nav-text">理解</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8E%9F%E7%90%86-14"><span class="nav-number">26.2.</span> <span class="nav-text">原理</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E4%BB%80%E4%B9%88%E6%98%AF%E4%BD%9C%E7%94%A8%E5%9F%9F%E6%8F%92%E6%A7%BD"><span class="nav-number">27.</span> <span class="nav-text">什么是作用域插槽?</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%90%86%E8%A7%A3-18"><span class="nav-number">27.1.</span> <span class="nav-text">理解</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#%E6%8F%92%E6%A7%BD"><span class="nav-number">27.1.1.</span> <span class="nav-text">插槽</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%E4%BD%9C%E7%94%A8%E5%9F%9F%E6%8F%92%E6%A7%BD"><span class="nav-number">27.1.2.</span> <span class="nav-text">作用域插槽</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8E%9F%E7%90%86-15"><span class="nav-number">27.2.</span> <span class="nav-text">原理</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#%E6%8F%92%E6%A7%BD-1"><span class="nav-number">27.2.1.</span> <span class="nav-text">插槽</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%BD%9C%E7%94%A8%E5%9F%9F%E6%8F%92%E6%A7%BD-1"><span class="nav-number">27.3.</span> <span class="nav-text">作用域插槽</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E8%B0%88%E8%B0%88%E4%BD%A0%E5%AF%B9-keep-alive-%E7%9A%84%E4%BA%86%E8%A7%A3%EF%BC%9F"><span class="nav-number">28.</span> <span class="nav-text">谈谈你对 keep-alive 的了解？</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%90%86%E8%A7%A3-19"><span class="nav-number">28.1.</span> <span class="nav-text">理解</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8E%9F%E7%90%86-16"><span class="nav-number">28.2.</span> <span class="nav-text">原理</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Vue%E4%B8%AD%E5%B8%B8%E8%A7%81%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96"><span class="nav-number">29.</span> <span class="nav-text">Vue中常见性能优化</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%BC%96%E7%A0%81%E4%BC%98%E5%8C%96"><span class="nav-number">29.1.</span> <span class="nav-text">编码优化</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Vue%E5%8A%A0%E8%BD%BD%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96"><span class="nav-number">29.2.</span> <span class="nav-text">Vue加载性能优化</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%94%A8%E6%88%B7%E4%BD%93%E9%AA%8C"><span class="nav-number">29.3.</span> <span class="nav-text">用户体验</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#SEO%E4%BC%98%E5%8C%96"><span class="nav-number">29.4.</span> <span class="nav-text">SEO优化</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%89%93%E5%8C%85%E4%BC%98%E5%8C%96"><span class="nav-number">29.5.</span> <span class="nav-text">打包优化</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%BC%93%E5%AD%98%EF%BC%8C%E5%8E%8B%E7%BC%A9"><span class="nav-number">29.6.</span> <span class="nav-text">缓存，压缩</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Vue3-0%E4%BD%A0%E7%9F%A5%E9%81%93%E6%9C%89%E5%93%AA%E4%BA%9B%E6%94%B9%E8%BF%9B"><span class="nav-number">30.</span> <span class="nav-text">Vue3.0你知道有哪些改进?</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%AE%9E%E7%8E%B0hash%E8%B7%AF%E7%94%B1%E5%92%8Chistory%E8%B7%AF%E7%94%B1"><span class="nav-number">31.</span> <span class="nav-text">实现hash路由和history路由</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Vue-Router%E4%B8%AD%E5%AF%BC%E8%88%AA%E5%AE%88%E5%8D%AB%E6%9C%89%E5%93%AA%E4%BA%9B%EF%BC%9F"><span class="nav-number">32.</span> <span class="nav-text">Vue-Router中导航守卫有哪些？</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%AE%8C%E6%95%B4%E7%9A%84%E5%AF%BC%E8%88%AA%E8%A7%A3%E6%9E%90%E6%B5%81%E7%A8%8B"><span class="nav-number">32.1.</span> <span class="nav-text">完整的导航解析流程</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#action-%E5%92%8C-mutation%E5%8C%BA%E5%88%AB"><span class="nav-number">33.</span> <span class="nav-text">action 和 mutation区别</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%AE%80%E8%BF%B0Vuex%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86"><span class="nav-number">34.</span> <span class="nav-text">简述Vuex工作原理</span></a></li></ol></div>
        </div>
        <!--/noindex-->

        <div class="site-overview-wrap sidebar-panel">
          <div class="site-author site-overview-item animated" itemprop="author" itemscope itemtype="http://schema.org/Person">
  <p class="site-author-name" itemprop="name">郭泽</p>
  <div class="site-description" itemprop="description"></div>
</div>
<div class="site-state-wrap site-overview-item animated">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
        <a href="/archives/">
          <span class="site-state-item-count">54</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
          <a href="/categories/">
        <span class="site-state-item-count">21</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
          <a href="/tags/">
        <span class="site-state-item-count">51</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>



        </div>
      </div>
    </div>
  </aside>
  <div class="sidebar-dimmer"></div>


    </header>

    
  <div class="back-to-top" role="button" aria-label="返回顶部">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>
  <a role="button" class="book-mark-link book-mark-link-fixed"></a>

<noscript>
  <div class="noscript-warning">Theme NexT works best with JavaScript enabled</div>
</noscript>


    <div class="main-inner post posts-expand">


  


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://gz1234.gitee.io/2020/10/21/vue%E7%AC%94%E8%AE%B0/vue-souce/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="郭泽">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="郭泽">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="vue2代码简单解析 | 郭泽">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          vue2代码简单解析
        </h1>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2020-10-21 10:07:09" itemprop="dateCreated datePublished" datetime="2020-10-21T10:07:09+08:00">2020-10-21</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar-check"></i>
      </span>
      <span class="post-meta-item-text">更新于</span>
      <time title="修改时间：2023-04-27 09:11:48" itemprop="dateModified" datetime="2023-04-27T09:11:48+08:00">2023-04-27</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/vue/" itemprop="url" rel="index"><span itemprop="name">vue</span></a>
        </span>
    </span>

  
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
        <h2 id="谈一下你对MVVM原理的理解"><a href="#谈一下你对MVVM原理的理解" class="headerlink" title="谈一下你对MVVM原理的理解"></a>谈一下你对<code>MVVM</code>原理的理解</h2><img src="/2020/10/21/vue%E7%AC%94%E8%AE%B0/vue-souce/MVVM.jpg" alt="MVVM" style="zoom: 50%;">

<ul>
<li>传统的<code>MVC</code>指的是,用户操作会请求服务端路由，路由会调用对应的控制器来处理,控制器会获取数据。将结果返回给前端,页面重新渲染</li>
<li><code>MVVM</code>:传统的前端会将数据手动渲染到页面上,<code>MVVM</code>模式不需要用户收到操作<code>dom</code>元素,将数据绑定到<code>viewModel</code>层上，会自动将数据渲染到页面中，视图变化会通知<code>viewModel层</code>更新数据。<code>ViewModel</code>就是我们<code>MVVM</code>模式中的桥梁.<a id="more"></a>
<h2 id="请说一下响应式数据的原理？"><a href="#请说一下响应式数据的原理？" class="headerlink" title="请说一下响应式数据的原理？"></a>请说一下响应式数据的原理？</h2></li>
</ul>
<h3 id="理解"><a href="#理解" class="headerlink" title="理解"></a>理解</h3><ul>
<li>核心点:<code>Object.defineProperty</code></li>
<li>默认<code>Vue</code>在初始化数据时，会给<code>data</code>中的属性使用<code>Object.defineProperty</code>重新定义所有属性,当页面取到对应属性时。会进行依赖收集（收集当前组件的watcher） 如果属性发生变化会通知相关依赖进行更新操作。</li>
</ul>
<h3 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理</h3><p><img src="/2020/10/21/vue%E7%AC%94%E8%AE%B0/vue-souce/%E5%93%8D%E5%BA%94%E5%BC%8F%E6%95%B0%E6%8D%AE%E5%8E%9F%E7%90%86.png"></p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">Object</span>.defineProperty(obj, key, &#123;</span><br><span class="line">    enumerable: <span class="literal">true</span>,</span><br><span class="line">    configurable: <span class="literal">true</span>,</span><br><span class="line">    get: <span class="function"><span class="keyword">function</span> <span class="title">reactiveGetter</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">      <span class="keyword">const</span> value = getter ? getter.call(obj) : val</span><br><span class="line">      <span class="keyword">if</span> (Dep.target) &#123;</span><br><span class="line">        dep.depend() <span class="comment">// ** 收集依赖 ** /</span></span><br><span class="line">        <span class="keyword">if</span> (childOb) &#123;</span><br><span class="line">          childOb.dep.depend()</span><br><span class="line">          <span class="keyword">if</span> (<span class="built_in">Array</span>.isArray(value)) &#123;</span><br><span class="line">            dependArray(value)</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">return</span> value</span><br><span class="line">    &#125;,</span><br><span class="line">    set: <span class="function"><span class="keyword">function</span> <span class="title">reactiveSetter</span> (<span class="params">newVal</span>) </span>&#123;</span><br><span class="line">      <span class="keyword">const</span> value = getter ? getter.call(obj) : val</span><br><span class="line">      <span class="keyword">if</span> (newVal === value || (newVal !== newVal &amp;&amp; value !== value)) &#123;</span><br><span class="line">        <span class="keyword">return</span></span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">if</span> (process.env.NODE_ENV !== <span class="string">&#x27;production&#x27;</span> &amp;&amp; customSetter) &#123;</span><br><span class="line">        customSetter()</span><br><span class="line">      &#125;</span><br><span class="line">      val = newVal</span><br><span class="line">      childOb = !shallow &amp;&amp; observe(newVal)</span><br><span class="line">      dep.notify() <span class="comment">/**通知相关依赖进行更新**/</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;)</span><br></pre></td></tr></table></figure>

<h2 id="Vue中是如何检测数组变化"><a href="#Vue中是如何检测数组变化" class="headerlink" title="Vue中是如何检测数组变化?"></a><code>Vue</code>中是如何检测数组变化?</h2><h3 id="理解-1"><a href="#理解-1" class="headerlink" title="理解"></a>理解</h3><ul>
<li>使用函数劫持的方式，重写了数组的方法</li>
<li><code>Vue</code>将<code>data</code>中的数组，进行了原型链重写。指向了自己定义的数组原型方法，这样当调用数组<code>api</code>时，可以通知依赖更新.如果数组中包含着引用类型。会对数组中的引用类型再次进行监控。</li>
</ul>
<h3 id="原理-1"><a href="#原理-1" class="headerlink" title="原理"></a>原理</h3><p><img src="/2020/10/21/vue%E7%AC%94%E8%AE%B0/vue-souce/%E6%95%B0%E7%BB%84%E5%93%8D%E5%BA%94%E5%BC%8F%E6%95%B0%E6%8D%AE%E5%8E%9F%E7%90%86.png"></p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> arrayProto = <span class="built_in">Array</span>.prototype</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> arrayMethods = <span class="built_in">Object</span>.create(arrayProto)</span><br><span class="line"><span class="keyword">const</span> methodsToPatch = [</span><br><span class="line">  <span class="string">&#x27;push&#x27;</span>,</span><br><span class="line">  <span class="string">&#x27;pop&#x27;</span>,</span><br><span class="line">  <span class="string">&#x27;shift&#x27;</span>,</span><br><span class="line">  <span class="string">&#x27;unshift&#x27;</span>,</span><br><span class="line">  <span class="string">&#x27;splice&#x27;</span>,</span><br><span class="line">  <span class="string">&#x27;sort&#x27;</span>,</span><br><span class="line">  <span class="string">&#x27;reverse&#x27;</span></span><br><span class="line">]</span><br><span class="line">methodsToPatch.forEach(<span class="function"><span class="keyword">function</span> (<span class="params">method</span>) </span>&#123; <span class="comment">// 重写原型方法</span></span><br><span class="line">  <span class="keyword">const</span> original = arrayProto[method] <span class="comment">// 调用原数组的方法</span></span><br><span class="line">  def(arrayMethods, method, <span class="function"><span class="keyword">function</span> <span class="title">mutator</span> (<span class="params">...args</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">const</span> result = original.apply(<span class="built_in">this</span>, args)</span><br><span class="line">    <span class="keyword">const</span> ob = <span class="built_in">this</span>.__ob__</span><br><span class="line">    <span class="keyword">let</span> inserted</span><br><span class="line">    <span class="keyword">switch</span> (method) &#123;</span><br><span class="line">      <span class="keyword">case</span> <span class="string">&#x27;push&#x27;</span>:</span><br><span class="line">      <span class="keyword">case</span> <span class="string">&#x27;unshift&#x27;</span>:</span><br><span class="line">        inserted = args</span><br><span class="line">        <span class="keyword">break</span></span><br><span class="line">      <span class="keyword">case</span> <span class="string">&#x27;splice&#x27;</span>:</span><br><span class="line">        inserted = args.slice(<span class="number">2</span>)</span><br><span class="line">        <span class="keyword">break</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (inserted) ob.observeArray(inserted)</span><br><span class="line">    <span class="comment">// notify change</span></span><br><span class="line">    ob.dep.notify() <span class="comment">// 当调用数组方法后，手动通知视图更新</span></span><br><span class="line">    <span class="keyword">return</span> result</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="built_in">this</span>.observeArray(value) <span class="comment">// 进行深度监控</span></span><br></pre></td></tr></table></figure>

<h2 id="为何Vue采用异步渲染"><a href="#为何Vue采用异步渲染" class="headerlink" title="为何Vue采用异步渲染?"></a>为何<code>Vue</code>采用异步渲染?</h2><h3 id="理解-2"><a href="#理解-2" class="headerlink" title="理解"></a>理解</h3><p>因为如果不采用异步更新，那么每次更新数据都会对当前组件进行重新渲染.所以为了性能考虑。<code>Vue</code>会在本轮数据更新后，再去异步更新视图!</p>
<h3 id="原理-2"><a href="#原理-2" class="headerlink" title="原理"></a>原理</h3><p><img src="/2020/10/21/vue%E7%AC%94%E8%AE%B0/vue-souce/%E4%B8%BA%E4%BD%95%E5%BC%82%E6%AD%A5%E6%B8%B2%E6%9F%93.png"></p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line">update () &#123;</span><br><span class="line">    <span class="comment">/* istanbul ignore else */</span></span><br><span class="line">    <span class="keyword">if</span> (<span class="built_in">this</span>.lazy) &#123;</span><br><span class="line">      <span class="built_in">this</span>.dirty = <span class="literal">true</span></span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (<span class="built_in">this</span>.sync) &#123;</span><br><span class="line">      <span class="built_in">this</span>.run()</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      queueWatcher(<span class="built_in">this</span>); <span class="comment">// 当数据发生变化时会将watcher放到一个队列中批量更新</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">queueWatcher</span> (<span class="params">watcher: Watcher</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">const</span> id = watcher.id <span class="comment">// 会对相同的watcher进行过滤</span></span><br><span class="line">  <span class="keyword">if</span> (has[id] == <span class="literal">null</span>) &#123;</span><br><span class="line">    has[id] = <span class="literal">true</span></span><br><span class="line">    <span class="keyword">if</span> (!flushing) &#123;</span><br><span class="line">      queue.push(watcher)</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      <span class="keyword">let</span> i = queue.length - <span class="number">1</span></span><br><span class="line">      <span class="keyword">while</span> (i &gt; index &amp;&amp; queue[i].id &gt; watcher.id) &#123;</span><br><span class="line">        i--</span><br><span class="line">      &#125;</span><br><span class="line">      queue.splice(i + <span class="number">1</span>, <span class="number">0</span>, watcher)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// queue the flush</span></span><br><span class="line">    <span class="keyword">if</span> (!waiting) &#123;</span><br><span class="line">      waiting = <span class="literal">true</span></span><br><span class="line"></span><br><span class="line">      <span class="keyword">if</span> (process.env.NODE_ENV !== <span class="string">&#x27;production&#x27;</span> &amp;&amp; !config.async) &#123;</span><br><span class="line">        flushSchedulerQueue()</span><br><span class="line">        <span class="keyword">return</span></span><br><span class="line">      &#125;</span><br><span class="line">      nextTick(flushSchedulerQueue) <span class="comment">// 调用nextTick方法 批量的进行更新</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="nextTick实现原理"><a href="#nextTick实现原理" class="headerlink" title="nextTick实现原理?"></a><code>nextTick</code>实现原理?</h2><h3 id="理解-宏任务和微任务-异步方法"><a href="#理解-宏任务和微任务-异步方法" class="headerlink" title="理解:(宏任务和微任务) 异步方法"></a>理解:(<strong>宏任务</strong>和<strong>微任务</strong>) 异步方法</h3><p><code>nextTick</code>方法主要是使用了<strong>宏任务</strong>和<strong>微任务</strong>,定义了一个异步方法.多次调用<code>nextTick</code> 会将方法存入队列中，通过这个异步方法清空当前队列。 所以这个<code>nextTick</code>方法就是异步方法</p>
<h3 id="原理-3"><a href="#原理-3" class="headerlink" title="原理"></a>原理</h3><p><img src="/2020/10/21/vue%E7%AC%94%E8%AE%B0/vue-souce/nextTick%E5%8E%9F%E7%90%86%E5%89%96%E6%9E%90.png"></p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> timerFunc  <span class="comment">// 会定义一个异步方法</span></span><br><span class="line"><span class="keyword">if</span> (<span class="keyword">typeof</span> <span class="built_in">Promise</span> !== <span class="string">&#x27;undefined&#x27;</span> &amp;&amp; isNative(<span class="built_in">Promise</span>)) &#123;  <span class="comment">// promise</span></span><br><span class="line">  <span class="keyword">const</span> p = <span class="built_in">Promise</span>.resolve()</span><br><span class="line">  timerFunc = <span class="function">() =&gt;</span> &#123;</span><br><span class="line">    p.then(flushCallbacks)</span><br><span class="line">    <span class="keyword">if</span> (isIOS) <span class="built_in">setTimeout</span>(noop)</span><br><span class="line">  &#125;</span><br><span class="line">  isUsingMicroTask = <span class="literal">true</span></span><br><span class="line">&#125; <span class="keyword">else</span> <span class="keyword">if</span> (!isIE &amp;&amp; <span class="keyword">typeof</span> MutationObserver !== <span class="string">&#x27;undefined&#x27;</span> &amp;&amp; ( <span class="comment">// MutationObserver</span></span><br><span class="line">  isNative(MutationObserver) ||</span><br><span class="line">  MutationObserver.toString() === <span class="string">&#x27;[object MutationObserverConstructor]&#x27;</span></span><br><span class="line">)) &#123;</span><br><span class="line">  <span class="keyword">let</span> counter = <span class="number">1</span></span><br><span class="line">  <span class="keyword">const</span> observer = <span class="keyword">new</span> MutationObserver(flushCallbacks)</span><br><span class="line">  <span class="keyword">const</span> textNode = <span class="built_in">document</span>.createTextNode(<span class="built_in">String</span>(counter))</span><br><span class="line">  observer.observe(textNode, &#123;</span><br><span class="line">    characterData: <span class="literal">true</span></span><br><span class="line">  &#125;)</span><br><span class="line">  timerFunc = <span class="function">() =&gt;</span> &#123;</span><br><span class="line">    counter = (counter + <span class="number">1</span>) % <span class="number">2</span></span><br><span class="line">    textNode.data = <span class="built_in">String</span>(counter)</span><br><span class="line">  &#125;</span><br><span class="line">  isUsingMicroTask = <span class="literal">true</span></span><br><span class="line">&#125; <span class="keyword">else</span> <span class="keyword">if</span> (<span class="keyword">typeof</span> setImmediate !== <span class="string">&#x27;undefined&#x27;</span> ) &#123; <span class="comment">// setImmediate</span></span><br><span class="line">  timerFunc = <span class="function">() =&gt;</span> &#123;</span><br><span class="line">    setImmediate(flushCallbacks)</span><br><span class="line">  &#125;</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">  timerFunc = <span class="function">() =&gt;</span> &#123;   <span class="comment">// setTimeout</span></span><br><span class="line">    <span class="built_in">setTimeout</span>(flushCallbacks, <span class="number">0</span>)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// nextTick实现</span></span><br><span class="line"><span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">nextTick</span> (<span class="params">cb?: <span class="built_in">Function</span>, ctx?: <span class="built_in">Object</span></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">let</span> _resolve</span><br><span class="line">  callbacks.push(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (cb) &#123;</span><br><span class="line">      <span class="keyword">try</span> &#123;</span><br><span class="line">        cb.call(ctx)</span><br><span class="line">      &#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line">        handleError(e, ctx, <span class="string">&#x27;nextTick&#x27;</span>)</span><br><span class="line">      &#125;</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (_resolve) &#123;</span><br><span class="line">      _resolve(ctx)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;)</span><br><span class="line">  <span class="keyword">if</span> (!pending) &#123;</span><br><span class="line">    pending = <span class="literal">true</span></span><br><span class="line">    timerFunc()</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h2 id="Vue中Computed的特点"><a href="#Vue中Computed的特点" class="headerlink" title="Vue中Computed的特点"></a><code>Vue</code>中<code>Computed</code>的特点</h2><h3 id="理解-3"><a href="#理解-3" class="headerlink" title="理解"></a>理解</h3><ul>
<li>默认<code>computed</code>也是一个<code>watcher</code>是具备缓存的，只要当依赖的属性发生变化时才会更新视图</li>
</ul>
<h3 id="原理-4"><a href="#原理-4" class="headerlink" title="原理"></a>原理</h3><p><img src="/2020/10/21/vue%E7%AC%94%E8%AE%B0/vue-souce/%E8%AE%A1%E7%AE%97%E5%B1%9E%E6%80%A7.png"></p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">initComputed</span> (<span class="params">vm: Component, computed: <span class="built_in">Object</span></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">const</span> watchers = vm._computedWatchers = <span class="built_in">Object</span>.create(<span class="literal">null</span>)</span><br><span class="line">  <span class="keyword">const</span> isSSR = isServerRendering()</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">const</span> key <span class="keyword">in</span> computed) &#123;</span><br><span class="line">    <span class="keyword">const</span> userDef = computed[key]</span><br><span class="line">    <span class="keyword">const</span> getter = <span class="keyword">typeof</span> userDef === <span class="string">&#x27;function&#x27;</span> ? userDef : userDef.get</span><br><span class="line">    <span class="keyword">if</span> (!isSSR) &#123;</span><br><span class="line">      <span class="comment">// create internal watcher for the computed property.</span></span><br><span class="line">      watchers[key] = <span class="keyword">new</span> Watcher(</span><br><span class="line">        vm,</span><br><span class="line">        getter || noop,</span><br><span class="line">        noop,</span><br><span class="line">        computedWatcherOptions</span><br><span class="line">      )</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// component-defined computed properties are already defined on the</span></span><br><span class="line">    <span class="comment">// component prototype. We only need to define computed properties defined</span></span><br><span class="line">    <span class="comment">// at instantiation here.</span></span><br><span class="line">    <span class="keyword">if</span> (!(key <span class="keyword">in</span> vm)) &#123;</span><br><span class="line">      defineComputed(vm, key, userDef)</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (process.env.NODE_ENV !== <span class="string">&#x27;production&#x27;</span>) &#123;</span><br><span class="line">      <span class="keyword">if</span> (key <span class="keyword">in</span> vm.$data) &#123;</span><br><span class="line">        warn(<span class="string">`The computed property &quot;<span class="subst">$&#123;key&#125;</span>&quot; is already defined in data.`</span>, vm)</span><br><span class="line">      &#125; <span class="keyword">else</span> <span class="keyword">if</span> (vm.$options.props &amp;&amp; key <span class="keyword">in</span> vm.$options.props) &#123;</span><br><span class="line">        warn(<span class="string">`The computed property &quot;<span class="subst">$&#123;key&#125;</span>&quot; is already defined as a prop.`</span>, vm)</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">createComputedGetter</span> (<span class="params">key</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="function"><span class="keyword">function</span> <span class="title">computedGetter</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">const</span> watcher = <span class="built_in">this</span>._computedWatchers &amp;&amp; <span class="built_in">this</span>._computedWatchers[key]</span><br><span class="line">    <span class="keyword">if</span> (watcher) &#123;</span><br><span class="line">      <span class="keyword">if</span> (watcher.dirty) &#123; <span class="comment">// 如果依赖的值没发生变化,就不会重新求值</span></span><br><span class="line">        watcher.evaluate()</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">if</span> (Dep.target) &#123;</span><br><span class="line">        watcher.depend()</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">return</span> watcher.value</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="Watch中的deep-true-是如何实现的"><a href="#Watch中的deep-true-是如何实现的" class="headerlink" title="Watch中的deep:true 是如何实现的"></a><code>Watch</code>中的<code>deep:true</code> 是如何实现的</h2><h3 id="理解-4"><a href="#理解-4" class="headerlink" title="理解"></a>理解</h3><ul>
<li>当用户指定了<code>watch</code>中的deep属性为<code>true</code>时，如果当前监控的值是数组类型。会对对象中的每一项进行求值，此时会将当前<code>watcher</code>存入到对应属性的依赖中，这样数组中对象发生变化时也会通知数据更新</li>
</ul>
<h3 id="原理-5"><a href="#原理-5" class="headerlink" title="原理"></a>原理</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line">get () &#123;</span><br><span class="line">    pushTarget(<span class="built_in">this</span>) <span class="comment">// 先将当前依赖放到 Dep.target上</span></span><br><span class="line">    <span class="keyword">let</span> value</span><br><span class="line">    <span class="keyword">const</span> vm = <span class="built_in">this</span>.vm</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      value = <span class="built_in">this</span>.getter.call(vm, vm)</span><br><span class="line">    &#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line">      <span class="keyword">if</span> (<span class="built_in">this</span>.user) &#123;</span><br><span class="line">        handleError(e, vm, <span class="string">`getter for watcher &quot;<span class="subst">$&#123;<span class="built_in">this</span>.expression&#125;</span>&quot;`</span>)</span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">throw</span> e</span><br><span class="line">      &#125;</span><br><span class="line">    &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">      <span class="keyword">if</span> (<span class="built_in">this</span>.deep) &#123; <span class="comment">// 如果需要深度监控</span></span><br><span class="line">        traverse(value) <span class="comment">// 会对对象中的每一项取值,取值时会执行对应的get方法</span></span><br><span class="line">      &#125;</span><br><span class="line">      popTarget()</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> value</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">_traverse</span> (<span class="params">val: any, seen: SimpleSet</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">let</span> i, keys</span><br><span class="line">  <span class="keyword">const</span> isA = <span class="built_in">Array</span>.isArray(val)</span><br><span class="line">  <span class="keyword">if</span> ((!isA &amp;&amp; !isObject(val)) || <span class="built_in">Object</span>.isFrozen(val) || val <span class="keyword">instanceof</span> VNode) &#123;</span><br><span class="line">    <span class="keyword">return</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> (val.__ob__) &#123;</span><br><span class="line">    <span class="keyword">const</span> depId = val.__ob__.dep.id</span><br><span class="line">    <span class="keyword">if</span> (seen.has(depId)) &#123;</span><br><span class="line">      <span class="keyword">return</span></span><br><span class="line">    &#125;</span><br><span class="line">    seen.add(depId)</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> (isA) &#123;</span><br><span class="line">    i = val.length</span><br><span class="line">    <span class="keyword">while</span> (i--) _traverse(val[i], seen)</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    keys = <span class="built_in">Object</span>.keys(val)</span><br><span class="line">    i = keys.length</span><br><span class="line">    <span class="keyword">while</span> (i--) _traverse(val[keys[i]], seen)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h2 id="Vue组件的生命周期"><a href="#Vue组件的生命周期" class="headerlink" title="Vue组件的生命周期"></a><code>Vue</code>组件的生命周期</h2><h3 id="理解-5"><a href="#理解-5" class="headerlink" title="理解"></a>理解</h3><h4 id="要掌握每个生命周期什么时候被调用"><a href="#要掌握每个生命周期什么时候被调用" class="headerlink" title="要掌握每个生命周期什么时候被调用"></a>要掌握每个生命周期什么时候被调用</h4><ul>
<li><code>beforeCreate</code> 在实例初始化之后，数据观测(data observer) 之前被调用。</li>
<li><code>created</code> 实例已经创建完成之后被调用。在这一步，实例已完成以下的配置：数据观测(data observer)，属性和方法的运算， watch/event 事件回调。这里没有$el</li>
<li><code>beforeMount</code> 在挂载开始之前被调用：相关的 render 函数首次被调用。</li>
<li><code>mounted</code> el 被新创建的 <code>vm.$el</code> 替换，并挂载到实例上去之后调用该钩子。</li>
<li><code>beforeUpdate</code> 数据更新时调用，发生在虚拟 DOM 重新渲染和打补丁之前。</li>
<li><code>updated</code> 由于数据更改导致的虚拟 DOM 重新渲染和打补丁，在这之后会调用该钩子。</li>
<li><code>beforeDestroy</code> 实例销毁之前调用。在这一步，实例仍然完全可用。</li>
<li><code>destroyed</code> <code>Vue</code> 实例销毁后调用。调用后，<code>Vue</code> 实例指示的所有东西都会解绑定，所有的事件监听器会被移除，所有的子实例也会被销毁。 该钩子在服务器端渲染期间不被调用。</li>
</ul>
<h4 id="要掌握每个生命周期内部可以做什么事"><a href="#要掌握每个生命周期内部可以做什么事" class="headerlink" title="要掌握每个生命周期内部可以做什么事"></a>要掌握每个生命周期内部可以做什么事</h4><ul>
<li><code>created</code> 实例已经创建完成，因为它是最早触发的原因可以进行一些数据，资源的请求。</li>
<li><code>mounted</code> 实例已经挂载完成，可以进行一些DOM操作</li>
<li><code>beforeUpdate</code> 可以在这个钩子中进一步地更改状态，这不会触发附加的重渲染过程。</li>
<li><code>updated</code> 可以执行依赖于 DOM 的操作。然而在大多数情况下，你应该避免在此期间更改状态，因为这可能会导致更新无限循环。 该钩子在服务器端渲染期间不被调用。</li>
<li><code>destroyed</code> 可以执行一些优化操作,清空定时器，解除绑定事件</li>
</ul>
<p><img src="/2020/10/21/vue%E7%AC%94%E8%AE%B0/vue-souce/lifecycle.png" alt="lifecycle"></p>
<h3 id="原理-6"><a href="#原理-6" class="headerlink" title="原理"></a>原理</h3><p><img src="/2020/10/21/vue%E7%AC%94%E8%AE%B0/vue-souce/%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F.png" alt="生命周期"></p>
<h2 id="ajax请求放在哪个生命周期中"><a href="#ajax请求放在哪个生命周期中" class="headerlink" title="ajax请求放在哪个生命周期中"></a><code>ajax</code>请求放在哪个生命周期中</h2><h3 id="理解-6"><a href="#理解-6" class="headerlink" title="理解"></a>理解</h3><ul>
<li>在created的时候，视图中的<code>dom</code>并没有渲染出来，所以此时如果直接去操<code>dom</code>节点，无法找到相关的元素</li>
<li>在mounted中，由于此时<code>dom</code>已经渲染出来了，所以可以直接操作<code>dom</code>节点</li>
</ul>
<p>一般情况下都放到<code>mounted</code>中,保证逻辑的统一性,因为生命周期是同步执行的，<code>ajax</code>是异步执行的</p>
<blockquote>
<p>服务端渲染不支持mounted方法，所以在服务端渲染的情况下统一放到created中</p>
</blockquote>
<h2 id="何时需要使用beforeDestroy"><a href="#何时需要使用beforeDestroy" class="headerlink" title="何时需要使用beforeDestroy"></a>何时需要使用<code>beforeDestroy</code></h2><h3 id="理解-7"><a href="#理解-7" class="headerlink" title="理解"></a>理解</h3><ul>
<li>可能在当前页面中使用了<code>$on</code>方法，那需要在组件销毁前解绑。</li>
<li>清除自己定义的定时器</li>
<li>解除事件的绑定 <code>scroll mousemove ....</code></li>
</ul>
<h2 id="Vue中模板编译原理"><a href="#Vue中模板编译原理" class="headerlink" title="Vue中模板编译原理"></a><code>Vue</code>中模板编译原理</h2><ul>
<li>将<code>template</code>转化成<code>render</code>函数</li>
</ul>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">baseCompile</span> (<span class="params"></span></span></span><br><span class="line"><span class="function"><span class="params">  template: string,</span></span></span><br><span class="line"><span class="function"><span class="params">  options: CompilerOptions</span></span></span><br><span class="line"><span class="function"><span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">const</span> ast = parse(template.trim(), options) <span class="comment">// 将模板转化成ast语法树</span></span><br><span class="line">  <span class="keyword">if</span> (options.optimize !== <span class="literal">false</span>) &#123;           <span class="comment">// 优化树</span></span><br><span class="line">    optimize(ast, options)</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">const</span> code = generate(ast, options)         <span class="comment">// 生成树</span></span><br><span class="line">  <span class="keyword">return</span> &#123;</span><br><span class="line">    ast,</span><br><span class="line">    render: code.render,</span><br><span class="line">    staticRenderFns: code.staticRenderFns</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> ncname = <span class="string">`[a-zA-Z_][\\-\\.0-9_a-zA-Z]*`</span>; </span><br><span class="line"><span class="keyword">const</span> qnameCapture = <span class="string">`((?:<span class="subst">$&#123;ncname&#125;</span>\\:)?<span class="subst">$&#123;ncname&#125;</span>)`</span>;</span><br><span class="line"><span class="keyword">const</span> startTagOpen = <span class="keyword">new</span> <span class="built_in">RegExp</span>(<span class="string">`^&lt;<span class="subst">$&#123;qnameCapture&#125;</span>`</span>); <span class="comment">// 标签开头的正则 捕获的内容是标签名</span></span><br><span class="line"><span class="keyword">const</span> endTag = <span class="keyword">new</span> <span class="built_in">RegExp</span>(<span class="string">`^&lt;\\/<span class="subst">$&#123;qnameCapture&#125;</span>[^&gt;]*&gt;`</span>); <span class="comment">// 匹配标签结尾的  &lt;/div&gt;</span></span><br><span class="line"><span class="keyword">const</span> attribute = <span class="regexp">/^\s*([^\s&quot;&#x27;&lt;&gt;\/=]+)(?:\s*(=)\s*(?:&quot;([^&quot;]*)&quot;+|&#x27;([^&#x27;]*)&#x27;+|([^\s&quot;&#x27;=&lt;&gt;`]+)))?/</span>; <span class="comment">// 匹配属性的</span></span><br><span class="line"><span class="keyword">const</span> startTagClose = <span class="regexp">/^\s*(\/?)&gt;/</span>; <span class="comment">// 匹配标签结束的  &gt;</span></span><br><span class="line"><span class="keyword">let</span> root;</span><br><span class="line"><span class="keyword">let</span> currentParent;</span><br><span class="line"><span class="keyword">let</span> stack = []</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">createASTElement</span>(<span class="params">tagName,attrs</span>)</span>&#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">        tag:tagName,</span><br><span class="line">        type:<span class="number">1</span>,</span><br><span class="line">        children:[],</span><br><span class="line">        attrs,</span><br><span class="line">        parent:<span class="literal">null</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">start</span>(<span class="params">tagName,attrs</span>)</span>&#123;</span><br><span class="line">    <span class="keyword">let</span> element = createASTElement(tagName,attrs);</span><br><span class="line">    <span class="function"><span class="title">if</span>(<span class="params">!root</span>)</span>&#123;</span><br><span class="line">        root = element;</span><br><span class="line">    &#125;</span><br><span class="line">    currentParent = element;</span><br><span class="line">    stack.push(element);</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">chars</span>(<span class="params">text</span>)</span>&#123;</span><br><span class="line">    currentParent.children.push(&#123;</span><br><span class="line">        type:<span class="number">3</span>,</span><br><span class="line">        text</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">end</span>(<span class="params">tagName</span>)</span>&#123;</span><br><span class="line">    <span class="keyword">const</span> element = stack[stack.length-<span class="number">1</span>];</span><br><span class="line">    stack.length --; </span><br><span class="line">    currentParent = stack[stack.length-<span class="number">1</span>];</span><br><span class="line">    <span class="function"><span class="title">if</span>(<span class="params">currentParent</span>)</span>&#123;</span><br><span class="line">        element.parent = currentParent;</span><br><span class="line">        currentParent.children.push(element)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">parseHTML</span>(<span class="params">html</span>)</span>&#123;</span><br><span class="line">    <span class="function"><span class="title">while</span>(<span class="params">html</span>)</span>&#123;</span><br><span class="line">        <span class="keyword">let</span> textEnd = html.indexOf(<span class="string">&#x27;&lt;&#x27;</span>);</span><br><span class="line">        <span class="function"><span class="title">if</span>(<span class="params">textEnd == <span class="number">0</span></span>)</span>&#123;</span><br><span class="line">            <span class="keyword">const</span> startTagMatch = parseStartTag();</span><br><span class="line">            <span class="function"><span class="title">if</span>(<span class="params">startTagMatch</span>)</span>&#123;</span><br><span class="line">                start(startTagMatch.tagName,startTagMatch.attrs);</span><br><span class="line">                <span class="keyword">continue</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">const</span> endTagMatch = html.match(endTag);</span><br><span class="line">            <span class="function"><span class="title">if</span>(<span class="params">endTagMatch</span>)</span>&#123;</span><br><span class="line">                advance(endTagMatch[<span class="number">0</span>].length);</span><br><span class="line">                end(endTagMatch[<span class="number">1</span>])</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">let</span> text;</span><br><span class="line">        <span class="function"><span class="title">if</span>(<span class="params">textEnd &gt;=<span class="number">0</span> </span>)</span>&#123;</span><br><span class="line">            text = html.substring(<span class="number">0</span>,textEnd)</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="function"><span class="title">if</span>(<span class="params">text</span>)</span>&#123;</span><br><span class="line">            advance(text.length);</span><br><span class="line">            chars(text);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">advance</span>(<span class="params">n</span>) </span>&#123;</span><br><span class="line">        html = html.substring(n);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">parseStartTag</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="keyword">const</span> start = html.match(startTagOpen);</span><br><span class="line">        <span class="function"><span class="title">if</span>(<span class="params">start</span>)</span>&#123;</span><br><span class="line">            <span class="keyword">const</span> match = &#123;</span><br><span class="line">                tagName:start[<span class="number">1</span>],</span><br><span class="line">                attrs:[]</span><br><span class="line">            &#125;</span><br><span class="line">            advance(start[<span class="number">0</span>].length);</span><br><span class="line">            <span class="keyword">let</span> attr,end</span><br><span class="line">            <span class="keyword">while</span>(!(end = html.match(startTagClose)) &amp;&amp; (attr=html.match(attribute)))&#123;</span><br><span class="line">                advance(attr[<span class="number">0</span>].length);</span><br><span class="line">                match.attrs.push(&#123;<span class="attr">name</span>:attr[<span class="number">1</span>],<span class="attr">value</span>:attr[<span class="number">3</span>]&#125;)</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="function"><span class="title">if</span>(<span class="params">end</span>)</span>&#123;</span><br><span class="line">                advance(end[<span class="number">0</span>].length);</span><br><span class="line">                <span class="keyword">return</span> match</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 生成语法树</span></span><br><span class="line">parseHTML(<span class="string">`&lt;div id=&quot;container&quot;&gt;&lt;p&gt;hello&lt;span&gt;zf&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;`</span>);</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">gen</span>(<span class="params">node</span>)</span>&#123;</span><br><span class="line">    <span class="function"><span class="title">if</span>(<span class="params">node.type == <span class="number">1</span></span>)</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> generate(node);</span><br><span class="line">    &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">`_v(<span class="subst">$&#123;<span class="built_in">JSON</span>.stringify(node.text)&#125;</span>)`</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">genChildren</span>(<span class="params">el</span>)</span>&#123;</span><br><span class="line">    <span class="keyword">const</span> children = el.children;</span><br><span class="line">    <span class="function"><span class="title">if</span>(<span class="params">el.children</span>)</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">`[<span class="subst">$&#123;children.map(c=&gt;gen(c)).join(<span class="string">&#x27;,&#x27;</span>)&#125;</span>]`</span></span><br><span class="line">    &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">genProps</span>(<span class="params">attrs</span>)</span>&#123;</span><br><span class="line">    <span class="keyword">let</span> str = <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">    <span class="function"><span class="title">for</span>(<span class="params"><span class="keyword">let</span> i = <span class="number">0</span>; i &lt; attrs.length;i++</span>)</span>&#123;</span><br><span class="line">        <span class="keyword">let</span> attr = attrs[i];</span><br><span class="line">        str+= <span class="string">`<span class="subst">$&#123;attr.name&#125;</span>:<span class="subst">$&#123;attr.value&#125;</span>,`</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">`&#123;attrs:&#123;<span class="subst">$&#123;str.slice(<span class="number">0</span>,-<span class="number">1</span>)&#125;</span>&#125;&#125;`</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">generate</span>(<span class="params">el</span>)</span>&#123;</span><br><span class="line">    <span class="keyword">let</span> children = genChildren(el);</span><br><span class="line">    <span class="keyword">let</span> code = <span class="string">`_c(&#x27;<span class="subst">$&#123;el.tag&#125;</span>&#x27;<span class="subst">$&#123;</span></span></span><br><span class="line"><span class="string"><span class="subst">        el.attrs.length? <span class="string">`,<span class="subst">$&#123;genProps(el.attrs)&#125;</span>`</span>:<span class="string">&#x27;&#x27;</span></span></span></span><br><span class="line"><span class="string"><span class="subst">    &#125;</span><span class="subst">$&#123;</span></span></span><br><span class="line"><span class="string"><span class="subst">        children? <span class="string">`,<span class="subst">$&#123;children&#125;</span>`</span>:<span class="string">&#x27;&#x27;</span></span></span></span><br><span class="line"><span class="string"><span class="subst">    &#125;</span>)`</span>;</span><br><span class="line">    <span class="keyword">return</span> code;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 根据语法树生成新的代码</span></span><br><span class="line"><span class="keyword">let</span> code = generate(root);</span><br><span class="line"><span class="keyword">let</span> render = <span class="string">`with(this)&#123;return <span class="subst">$&#123;code&#125;</span>&#125;`</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 包装成函数</span></span><br><span class="line"><span class="keyword">let</span> renderFn = <span class="keyword">new</span> <span class="built_in">Function</span>(render);</span><br><span class="line"><span class="built_in">console</span>.log(renderFn.toString());</span><br></pre></td></tr></table></figure>

<h2 id="Vue中v-if和v-show的区别"><a href="#Vue中v-if和v-show的区别" class="headerlink" title="Vue中v-if和v-show的区别"></a><code>Vue</code>中<code>v-if</code>和<code>v-show</code>的区别</h2><h3 id="理解-8"><a href="#理解-8" class="headerlink" title="理解"></a>理解</h3><ul>
<li><code>v-if</code>如果条件不成立不会渲染当前指令所在节点的<code>dom</code>元素</li>
<li><code>v-show</code>只是切换当前<code>dom</code>的显示或者隐藏</li>
</ul>
<h3 id="原理-7"><a href="#原理-7" class="headerlink" title="原理"></a>原理</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> VueTemplateCompiler = <span class="built_in">require</span>(<span class="string">&#x27;vue-template-compiler&#x27;</span>);</span><br><span class="line"><span class="keyword">let</span> r1 = VueTemplateCompiler.compile(<span class="string">`&lt;div v-if=&quot;true&quot;&gt;&lt;span v-for=&quot;i in 3&quot;&gt;hello&lt;/span&gt;&lt;/div&gt;`</span>);</span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">with(this) &#123;</span></span><br><span class="line"><span class="comment">    return (true) ? _c(&#x27;div&#x27;, _l((3), function (i) &#123;</span></span><br><span class="line"><span class="comment">        return _c(&#x27;span&#x27;, [_v(&quot;hello&quot;)])</span></span><br><span class="line"><span class="comment">    &#125;), 0) : _e()</span></span><br><span class="line"><span class="comment">&#125;</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure>

<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> VueTemplateCompiler = <span class="built_in">require</span>(<span class="string">&#x27;vue-template-compiler&#x27;</span>);</span><br><span class="line"><span class="keyword">let</span> r2 = VueTemplateCompiler.compile(<span class="string">`&lt;div v-show=&quot;true&quot;&gt;&lt;/div&gt;`</span>);</span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">with(this) &#123;</span></span><br><span class="line"><span class="comment">    return _c(&#x27;div&#x27;, &#123;</span></span><br><span class="line"><span class="comment">        directives: [&#123;</span></span><br><span class="line"><span class="comment">            name: &quot;show&quot;,</span></span><br><span class="line"><span class="comment">            rawName: &quot;v-show&quot;,</span></span><br><span class="line"><span class="comment">            value: (true),</span></span><br><span class="line"><span class="comment">            expression: &quot;true&quot;</span></span><br><span class="line"><span class="comment">        &#125;]</span></span><br><span class="line"><span class="comment">    &#125;)</span></span><br><span class="line"><span class="comment">&#125;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// v-show 操作的是样式  定义在platforms/web/runtime/directives/show.js</span></span><br><span class="line">bind (el: any, &#123; value &#125;: VNodeDirective, <span class="attr">vnode</span>: VNodeWithData) &#123;</span><br><span class="line">    vnode = locateNode(vnode)</span><br><span class="line">    <span class="keyword">const</span> transition = vnode.data &amp;&amp; vnode.data.transition</span><br><span class="line">    <span class="keyword">const</span> originalDisplay = el.__vOriginalDisplay =</span><br><span class="line">      el.style.display === <span class="string">&#x27;none&#x27;</span> ? <span class="string">&#x27;&#x27;</span> : el.style.display</span><br><span class="line">    <span class="keyword">if</span> (value &amp;&amp; transition) &#123;</span><br><span class="line">      vnode.data.show = <span class="literal">true</span></span><br><span class="line">      enter(vnode, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">        el.style.display = originalDisplay</span><br><span class="line">      &#125;)</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      el.style.display = value ? originalDisplay : <span class="string">&#x27;none&#x27;</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="为什么V-for和v-if不能连用"><a href="#为什么V-for和v-if不能连用" class="headerlink" title="为什么V-for和v-if不能连用"></a>为什么<code>V-for</code>和<code>v-if</code>不能连用</h2><h3 id="理解-9"><a href="#理解-9" class="headerlink" title="理解"></a>理解</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> VueTemplateCompiler = <span class="built_in">require</span>(<span class="string">&#x27;vue-template-compiler&#x27;</span>);</span><br><span class="line"><span class="keyword">let</span> r1 = VueTemplateCompiler.compile(<span class="string">`&lt;div v-if=&quot;false&quot; v-for=&quot;i in 3&quot;&gt;hello&lt;/div&gt;`</span>);</span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">with(this) &#123;</span></span><br><span class="line"><span class="comment">    return _l((3), function (i) &#123;</span></span><br><span class="line"><span class="comment">        return (false) ? _c(&#x27;div&#x27;, [_v(&quot;hello&quot;)]) : _e()</span></span><br><span class="line"><span class="comment">    &#125;)</span></span><br><span class="line"><span class="comment">&#125;</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="built_in">console</span>.log(r1.render);</span><br></pre></td></tr></table></figure>

<ul>
<li><code>v-for</code>会比<code>v-if</code>的优先级高一些,如果连用的话会把<code>v-if</code>给每个元素都添加一下,会造成性能问题</li>
</ul>
<h2 id="用vnode来描述一个DOM结构"><a href="#用vnode来描述一个DOM结构" class="headerlink" title="用vnode来描述一个DOM结构"></a>用<code>vnode</code>来描述一个<code>DOM</code>结构</h2><ul>
<li>虚拟节点就是用一个对象来描述真实的<code>dom</code>元素</li>
</ul>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">$createElement</span>(<span class="params">tag,data,...children</span>)</span>&#123;</span><br><span class="line">    <span class="keyword">let</span> key = data.key;</span><br><span class="line">    <span class="keyword">delete</span> data.key;</span><br><span class="line">    children = children.map(<span class="function"><span class="params">child</span>=&gt;</span>&#123;</span><br><span class="line">        <span class="function"><span class="title">if</span>(<span class="params"><span class="keyword">typeof</span> child === <span class="string">&#x27;object&#x27;</span></span>)</span>&#123;</span><br><span class="line">            <span class="keyword">return</span> child</span><br><span class="line">        &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">            <span class="keyword">return</span> vnode(<span class="literal">undefined</span>,<span class="literal">undefined</span>,<span class="literal">undefined</span>,<span class="literal">undefined</span>,child)</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">    <span class="keyword">return</span> vnode(tag,props,key,children);</span><br><span class="line">&#125; </span><br><span class="line"><span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">vnode</span>(<span class="params">tag,data,key,children,text</span>)</span>&#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">        tag, <span class="comment">// 表示的是当前的标签名</span></span><br><span class="line">        data, <span class="comment">// 表示的是当前标签上的属性</span></span><br><span class="line">        key, <span class="comment">// 唯一表示用户可能传递</span></span><br><span class="line">        children,</span><br><span class="line">        text</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="diff算法的时间复杂度"><a href="#diff算法的时间复杂度" class="headerlink" title="diff算法的时间复杂度"></a><code>diff</code>算法的时间复杂度</h2><p> 两个树的完全的<code>diff</code>算法是一个时间复杂度为 <code>O(n3)</code>,<code>Vue</code>进行了优化·<em>O(n3)</em> <em>复杂度</em>的问题转换成 O(n) <em>复杂度</em>的问题(只比较同级不考虑跨级问题)  在前端当中， 你很少会跨越层级地移动Dom元素。 所以 Virtual Dom只会对同一个层级的元素进行对比。</p>
<h2 id="简述Vue中diff算法原理"><a href="#简述Vue中diff算法原理" class="headerlink" title="简述Vue中diff算法原理"></a>简述<code>Vue</code>中<code>diff</code>算法原理</h2><h3 id="理解-10"><a href="#理解-10" class="headerlink" title="理解"></a>理解</h3><ul>
<li>先同级比较，在比较子节点</li>
<li>先判断一方有儿子一方没儿子的情况</li>
<li>比较都有儿子的情况</li>
<li>递归比较子节点</li>
</ul>
<p><img src="/2020/10/21/vue%E7%AC%94%E8%AE%B0/vue-souce/vue-diff.jpg"></p>
<h3 id="原理-8"><a href="#原理-8" class="headerlink" title="原理"></a>原理</h3><blockquote>
<p><code>core/vdom/patch.js</code></p>
</blockquote>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> oldCh = oldVnode.children <span class="comment">// 老的儿子 </span></span><br><span class="line"><span class="keyword">const</span> ch = vnode.children  <span class="comment">// 新的儿子</span></span><br><span class="line"><span class="keyword">if</span> (isUndef(vnode.text)) &#123;</span><br><span class="line">    <span class="keyword">if</span> (isDef(oldCh) &amp;&amp; isDef(ch)) &#123;</span><br><span class="line">        <span class="comment">// 比较孩子</span></span><br><span class="line">        <span class="keyword">if</span> (oldCh !== ch) updateChildren(elm, oldCh, ch, insertedVnodeQueue, removeOnly)</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (isDef(ch)) &#123; <span class="comment">// 新的儿子有 老的没有</span></span><br><span class="line">        <span class="keyword">if</span> (isDef(oldVnode.text)) nodeOps.setTextContent(elm, <span class="string">&#x27;&#x27;</span>)</span><br><span class="line">        addVnodes(elm, <span class="literal">null</span>, ch, <span class="number">0</span>, ch.length - <span class="number">1</span>, insertedVnodeQueue)</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (isDef(oldCh)) &#123; <span class="comment">// 如果老的有新的没有 就删除</span></span><br><span class="line">        removeVnodes(oldCh, <span class="number">0</span>, oldCh.length - <span class="number">1</span>)</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (isDef(oldVnode.text)) &#123;  <span class="comment">// 老的有文本 新的没文本</span></span><br><span class="line">        nodeOps.setTextContent(elm, <span class="string">&#x27;&#x27;</span>) <span class="comment">// 将老的清空</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125; <span class="keyword">else</span> <span class="keyword">if</span> (oldVnode.text !== vnode.text) &#123; <span class="comment">// 文本不相同替换</span></span><br><span class="line">    nodeOps.setTextContent(elm, vnode.text)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">updateChildren</span> (<span class="params">parentElm, oldCh, newCh, insertedVnodeQueue, removeOnly</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> oldStartIdx = <span class="number">0</span></span><br><span class="line">    <span class="keyword">let</span> newStartIdx = <span class="number">0</span></span><br><span class="line">    <span class="keyword">let</span> oldEndIdx = oldCh.length - <span class="number">1</span></span><br><span class="line">    <span class="keyword">let</span> oldStartVnode = oldCh[<span class="number">0</span>]</span><br><span class="line">    <span class="keyword">let</span> oldEndVnode = oldCh[oldEndIdx]</span><br><span class="line">    <span class="keyword">let</span> newEndIdx = newCh.length - <span class="number">1</span></span><br><span class="line">    <span class="keyword">let</span> newStartVnode = newCh[<span class="number">0</span>]</span><br><span class="line">    <span class="keyword">let</span> newEndVnode = newCh[newEndIdx]</span><br><span class="line">    <span class="keyword">let</span> oldKeyToIdx, idxInOld, vnodeToMove, refElm</span><br><span class="line"></span><br><span class="line">    <span class="comment">// removeOnly is a special flag used only by &lt;transition-group&gt;</span></span><br><span class="line">    <span class="comment">// to ensure removed elements stay in correct relative positions</span></span><br><span class="line">    <span class="comment">// during leaving transitions</span></span><br><span class="line">    <span class="keyword">const</span> canMove = !removeOnly</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (process.env.NODE_ENV !== <span class="string">&#x27;production&#x27;</span>) &#123;</span><br><span class="line">      checkDuplicateKeys(newCh)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">while</span> (oldStartIdx &lt;= oldEndIdx &amp;&amp; newStartIdx &lt;= newEndIdx) &#123;</span><br><span class="line">      <span class="keyword">if</span> (isUndef(oldStartVnode)) &#123;</span><br><span class="line">        oldStartVnode = oldCh[++oldStartIdx] <span class="comment">// Vnode has been moved left</span></span><br><span class="line">      &#125; <span class="keyword">else</span> <span class="keyword">if</span> (isUndef(oldEndVnode)) &#123;</span><br><span class="line">        oldEndVnode = oldCh[--oldEndIdx]</span><br><span class="line">      &#125; <span class="keyword">else</span> <span class="keyword">if</span> (sameVnode(oldStartVnode, newStartVnode)) &#123;</span><br><span class="line">        patchVnode(oldStartVnode, newStartVnode, insertedVnodeQueue, newCh, newStartIdx)</span><br><span class="line">        oldStartVnode = oldCh[++oldStartIdx]</span><br><span class="line">        newStartVnode = newCh[++newStartIdx]</span><br><span class="line">      &#125; <span class="keyword">else</span> <span class="keyword">if</span> (sameVnode(oldEndVnode, newEndVnode)) &#123;</span><br><span class="line">        patchVnode(oldEndVnode, newEndVnode, insertedVnodeQueue, newCh, newEndIdx)</span><br><span class="line">        oldEndVnode = oldCh[--oldEndIdx]</span><br><span class="line">        newEndVnode = newCh[--newEndIdx]</span><br><span class="line">      &#125; <span class="keyword">else</span> <span class="keyword">if</span> (sameVnode(oldStartVnode, newEndVnode)) &#123; <span class="comment">// Vnode moved right</span></span><br><span class="line">        patchVnode(oldStartVnode, newEndVnode, insertedVnodeQueue, newCh, newEndIdx)</span><br><span class="line">        canMove &amp;&amp; nodeOps.insertBefore(parentElm, oldStartVnode.elm, nodeOps.nextSibling(oldEndVnode.elm))</span><br><span class="line">        oldStartVnode = oldCh[++oldStartIdx]</span><br><span class="line">        newEndVnode = newCh[--newEndIdx]</span><br><span class="line">      &#125; <span class="keyword">else</span> <span class="keyword">if</span> (sameVnode(oldEndVnode, newStartVnode)) &#123; <span class="comment">// Vnode moved left</span></span><br><span class="line">        patchVnode(oldEndVnode, newStartVnode, insertedVnodeQueue, newCh, newStartIdx)</span><br><span class="line">        canMove &amp;&amp; nodeOps.insertBefore(parentElm, oldEndVnode.elm, oldStartVnode.elm)</span><br><span class="line">        oldEndVnode = oldCh[--oldEndIdx]</span><br><span class="line">        newStartVnode = newCh[++newStartIdx]</span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (isUndef(oldKeyToIdx)) oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx)</span><br><span class="line">        idxInOld = isDef(newStartVnode.key)</span><br><span class="line">          ? oldKeyToIdx[newStartVnode.key]</span><br><span class="line">          : findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx)</span><br><span class="line">        <span class="keyword">if</span> (isUndef(idxInOld)) &#123; <span class="comment">// New element</span></span><br><span class="line">          createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, <span class="literal">false</span>, newCh, newStartIdx)</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">          vnodeToMove = oldCh[idxInOld]</span><br><span class="line">          <span class="keyword">if</span> (sameVnode(vnodeToMove, newStartVnode)) &#123;</span><br><span class="line">            patchVnode(vnodeToMove, newStartVnode, insertedVnodeQueue, newCh, newStartIdx)</span><br><span class="line">            oldCh[idxInOld] = <span class="literal">undefined</span></span><br><span class="line">            canMove &amp;&amp; nodeOps.insertBefore(parentElm, vnodeToMove.elm, oldStartVnode.elm)</span><br><span class="line">          &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">// same key but different element. treat as new element</span></span><br><span class="line">            createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, <span class="literal">false</span>, newCh, newStartIdx)</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        newStartVnode = newCh[++newStartIdx]</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (oldStartIdx &gt; oldEndIdx) &#123;</span><br><span class="line">      refElm = isUndef(newCh[newEndIdx + <span class="number">1</span>]) ? <span class="literal">null</span> : newCh[newEndIdx + <span class="number">1</span>].elm</span><br><span class="line">      addVnodes(parentElm, refElm, newCh, newStartIdx, newEndIdx, insertedVnodeQueue)</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (newStartIdx &gt; newEndIdx) &#123;</span><br><span class="line">      removeVnodes(oldCh, oldStartIdx, oldEndIdx)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure>

<h2 id="v-for中为什么要用key-图解"><a href="#v-for中为什么要用key-图解" class="headerlink" title="v-for中为什么要用key (图解)"></a><code>v-for</code>中为什么要用<code>key</code> (图解)</h2><p><img src="/2020/10/21/vue%E7%AC%94%E8%AE%B0/vue-souce/diff-key.jpg"></p>
<h2 id="描述组件渲染和更新过程"><a href="#描述组件渲染和更新过程" class="headerlink" title="描述组件渲染和更新过程"></a>描述组件渲染和更新过程</h2><h3 id="理解-11"><a href="#理解-11" class="headerlink" title="理解"></a>理解</h3><ul>
<li>渲染组件时，会通过<code>Vue.extend</code>方法构建子组件的构造函数，并进行实例化。最终手动调用<code>$mount()</code>进行挂载。更新组件时会进行<code>patchVnode</code>流程.核心就是diff算法</li>
</ul>
<p><img src="/2020/10/21/vue%E7%AC%94%E8%AE%B0/vue-souce/%E7%BB%84%E4%BB%B6%E6%B8%B2%E6%9F%93%E6%B5%81%E7%A8%8B.png"></p>
<h2 id="组件中的-data为什么是一个函数"><a href="#组件中的-data为什么是一个函数" class="headerlink" title="组件中的 data为什么是一个函数?"></a>组件中的 <code>data</code>为什么是一个函数?</h2><h3 id="理解-12"><a href="#理解-12" class="headerlink" title="理解"></a>理解</h3><p>同一个组件被复用多次，会创建多个实例。这些实例用的是同一个构造函数，如果<code>data</code>是一个对象的话。那么所有组件都共享了同一个对象。为了保证组件的数据独立性要求每个组件必须通过<code>data</code>函数返回一个对象作为组件的状态。</p>
<h3 id="原理-9"><a href="#原理-9" class="headerlink" title="原理"></a>原理</h3><blockquote>
<p><code>core/global-api/extend.js line:33</code></p>
</blockquote>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line">Sub.options = mergeOptions(</span><br><span class="line">      Super.options,</span><br><span class="line">      extendOptions</span><br><span class="line">)</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">mergeOptions</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">   <span class="function"><span class="keyword">function</span> <span class="title">mergeField</span> (<span class="params">key</span>) </span>&#123;</span><br><span class="line">        <span class="keyword">const</span> strat = strats[key] || defaultStrat</span><br><span class="line">        options[key] = strat(parent[key], child[key], vm, key)</span><br><span class="line">     &#125;</span><br><span class="line">&#125;</span><br><span class="line">strats.data = <span class="function"><span class="keyword">function</span> (<span class="params"> </span></span></span><br><span class="line"><span class="function"><span class="params">  parentVal: any,</span></span></span><br><span class="line"><span class="function"><span class="params">  childVal: any,</span></span></span><br><span class="line"><span class="function"><span class="params">  vm?: Component</span></span></span><br><span class="line"><span class="function"><span class="params"></span>): ?<span class="title">Function</span> </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (!vm) &#123; <span class="comment">// 合并是会判断子类的data必须是一个函数</span></span><br><span class="line">    <span class="keyword">if</span> (childVal &amp;&amp; <span class="keyword">typeof</span> childVal !== <span class="string">&#x27;function&#x27;</span>) &#123;</span><br><span class="line">      process.env.NODE_ENV !== <span class="string">&#x27;production&#x27;</span> &amp;&amp; warn(</span><br><span class="line">        <span class="string">&#x27;The &quot;data&quot; option should be a function &#x27;</span> +</span><br><span class="line">        <span class="string">&#x27;that returns a per-instance value in component &#x27;</span> +</span><br><span class="line">        <span class="string">&#x27;definitions.&#x27;</span>,</span><br><span class="line">        vm</span><br><span class="line">      )</span><br><span class="line"></span><br><span class="line">      <span class="keyword">return</span> parentVal</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> mergeDataOrFn(parentVal, childVal)</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> mergeDataOrFn(parentVal, childVal, vm)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<ul>
<li>一个组件被使用多次，用的都是同一个构造函数。为了保证组件的不同的实例data不冲突，要求data必须是一个函数，这样组件间不会相互影响</li>
</ul>
<h2 id="Vue中事件绑定的原理"><a href="#Vue中事件绑定的原理" class="headerlink" title="Vue中事件绑定的原理"></a><code>Vue</code>中事件绑定的原理</h2><h3 id="理解-13"><a href="#理解-13" class="headerlink" title="理解"></a>理解</h3><ul>
<li>原生<code>dom</code>事件的绑定,采用的是<code>addEventListener</code>实现</li>
<li>组件绑定事件采用的是<code>$on</code>方法</li>
</ul>
<h3 id="原理-10"><a href="#原理-10" class="headerlink" title="原理"></a>原理</h3><ul>
<li>事件的编译：</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> compiler = <span class="built_in">require</span>(<span class="string">&#x27;vue-template-compiler&#x27;</span>);</span><br><span class="line"><span class="keyword">let</span> r1 = compiler.compile(<span class="string">&#x27;&lt;div @click=&quot;fn()&quot;&gt;&lt;/div&gt;&#x27;</span>);</span><br><span class="line"><span class="keyword">let</span> r2 = compiler.compile(<span class="string">&#x27;&lt;my-component @click.native=&quot;fn&quot; @click=&quot;fn1&quot;&gt;&lt;/my-component&gt;&#x27;</span>);</span><br><span class="line"><span class="built_in">console</span>.log(r1); <span class="comment">// &#123;on:&#123;click&#125;&#125;</span></span><br><span class="line"><span class="built_in">console</span>.log(r2); <span class="comment">// &#123;nativeOnOn:&#123;click&#125;,on:&#123;click&#125;&#125;  </span></span><br></pre></td></tr></table></figure>

<p><img src="/2020/10/21/vue%E7%AC%94%E8%AE%B0/vue-souce/%E4%BA%8B%E4%BB%B6%E5%88%9D%E5%A7%8B%E5%8C%96.png"></p>
<h4 id="原生dom的绑定"><a href="#原生dom的绑定" class="headerlink" title="原生dom的绑定"></a>原生<code>dom</code>的绑定</h4><ul>
<li><code>Vue</code>在创建真是<code>dom</code>时会调用<code>createElm</code>,默认会调用<code>invokeCreateHooks</code></li>
<li>会遍历当前平台下相对的属性处理代码,其中就有<code>updateDOMListeners</code>方法,内部会传入<code>add</code>方法</li>
</ul>
<p>yuan</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">updateDOMListeners</span> (<span class="params">oldVnode: VNodeWithData, vnode: VNodeWithData</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (isUndef(oldVnode.data.on) &amp;&amp; isUndef(vnode.data.on)) &#123;</span><br><span class="line">    <span class="keyword">return</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">const</span> on = vnode.data.on || &#123;&#125;</span><br><span class="line">  <span class="keyword">const</span> oldOn = oldVnode.data.on || &#123;&#125;</span><br><span class="line">  target = vnode.elm</span><br><span class="line">  normalizeEvents(on)</span><br><span class="line">  updateListeners(on, oldOn, add, remove, createOnceHandler, vnode.context)</span><br><span class="line">  target = <span class="literal">undefined</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">add</span> (<span class="params"></span></span></span><br><span class="line"><span class="function"><span class="params">  name: string,</span></span></span><br><span class="line"><span class="function"><span class="params">  handler: <span class="built_in">Function</span>,</span></span></span><br><span class="line"><span class="function"><span class="params">  capture: boolean,</span></span></span><br><span class="line"><span class="function"><span class="params">  passive: boolean</span></span></span><br><span class="line"><span class="function"><span class="params"></span>) </span>&#123;</span><br><span class="line">  target.addEventListener( <span class="comment">// 给当前的dom添加事件</span></span><br><span class="line">    name,</span><br><span class="line">    handler,</span><br><span class="line">    supportsPassive</span><br><span class="line">      ? &#123; capture, passive &#125;</span><br><span class="line">      : capture</span><br><span class="line">  )</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p><code>vue</code>中绑定事件是直接绑定给真实<code>dom</code>元素的</p>
</blockquote>
<ul>
<li>组件中绑定事件</li>
</ul>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">updateComponentListeners</span> (<span class="params"></span></span></span><br><span class="line"><span class="function"><span class="params">  vm: Component,</span></span></span><br><span class="line"><span class="function"><span class="params">  listeners: <span class="built_in">Object</span>,</span></span></span><br><span class="line"><span class="function"><span class="params">  oldListeners: ?<span class="built_in">Object</span></span></span></span><br><span class="line"><span class="function"><span class="params"></span>) </span>&#123;</span><br><span class="line">  target = vm</span><br><span class="line">  updateListeners(listeners, oldListeners || &#123;&#125;, add, remove, createOnceHandler, vm)</span><br><span class="line">  target = <span class="literal">undefined</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">add</span> (<span class="params">event, fn</span>) </span>&#123;</span><br><span class="line">  target.$on(event, fn)</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<blockquote>
<p>组件绑定事件是通过<code>vue</code>中自定义的<code>$on</code>方法来实现的</p>
</blockquote>
<h2 id="v-model中的实现原理及如何自定义v-model"><a href="#v-model中的实现原理及如何自定义v-model" class="headerlink" title="v-model中的实现原理及如何自定义v-model"></a><code>v-model</code>中的实现原理及如何自定义<code>v-model</code></h2><h3 id="理解-14"><a href="#理解-14" class="headerlink" title="理解"></a>理解</h3><p>组件的<code>v-model</code>是<code>value+input方法</code>的语法糖</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">el-checkbox</span> <span class="attr">:value</span>=<span class="string">&quot;&quot;</span> @<span class="attr">input</span>=<span class="string">&quot;&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">el-checkbox</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">el-checkbox</span> <span class="attr">v-model</span>=<span class="string">&quot;check&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">el-checkbox</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>可以自己重新定义<code>v-model</code>的含义</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">Vue.component(<span class="string">&#x27;el-checkbox&#x27;</span>,&#123;</span><br><span class="line">    template:<span class="string">`&lt;input type=&quot;checkbox&quot; :checked=&quot;check&quot; @change=&quot;$emit(&#x27;change&#x27;,$event.target.checked)&quot;&gt;`</span>,</span><br><span class="line">    model:&#123;</span><br><span class="line">        prop:<span class="string">&#x27;check&#x27;</span>, <span class="comment">// 更改默认的value的名字</span></span><br><span class="line">        event:<span class="string">&#x27;change&#x27;</span> <span class="comment">// 更改默认的方法名</span></span><br><span class="line">    &#125;,</span><br><span class="line">    props: &#123;</span><br><span class="line">        check: <span class="built_in">Boolean</span></span><br><span class="line">    &#125;,</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<h3 id="原理-11"><a href="#原理-11" class="headerlink" title="原理"></a>原理</h3><ul>
<li>会将组件的<code>v-model</code>默认转化成value+input</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> VueTemplateCompiler = <span class="built_in">require</span>(<span class="string">&#x27;vue-template-compiler&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> ele = VueTemplateCompiler.compile(<span class="string">&#x27;&lt;el-checkbox v-model=&quot;check&quot;&gt;&lt;/el-checkbox&gt;&#x27;</span>);</span><br><span class="line"><span class="comment">// with(this) &#123;</span></span><br><span class="line"><span class="comment">//     return _c(&#x27;el-checkbox&#x27;, &#123;</span></span><br><span class="line"><span class="comment">//         model: &#123;</span></span><br><span class="line"><span class="comment">//             value: (check),</span></span><br><span class="line"><span class="comment">//             callback: function ($$v) &#123;</span></span><br><span class="line"><span class="comment">//                 check = $$v</span></span><br><span class="line"><span class="comment">//             &#125;,</span></span><br><span class="line"><span class="comment">//             expression: &quot;check&quot;</span></span><br><span class="line"><span class="comment">//         &#125;</span></span><br><span class="line"><span class="comment">//     &#125;)</span></span><br><span class="line"><span class="comment">// &#125;</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p><code>core/vdom/create-component.js  line:155</code></p>
</blockquote>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">transformModel</span> (<span class="params">options, data: any</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">const</span> prop = (options.model &amp;&amp; options.model.prop) || <span class="string">&#x27;value&#x27;</span></span><br><span class="line">  <span class="keyword">const</span> event = (options.model &amp;&amp; options.model.event) || <span class="string">&#x27;input&#x27;</span></span><br><span class="line">  ;(data.attrs || (data.attrs = &#123;&#125;))[prop] = data.model.value</span><br><span class="line">  <span class="keyword">const</span> on = data.on || (data.on = &#123;&#125;)</span><br><span class="line">  <span class="keyword">const</span> existing = on[event]</span><br><span class="line">  <span class="keyword">const</span> callback = data.model.callback</span><br><span class="line">  <span class="keyword">if</span> (isDef(existing)) &#123;</span><br><span class="line">    <span class="keyword">if</span> (</span><br><span class="line">      <span class="built_in">Array</span>.isArray(existing)</span><br><span class="line">        ? existing.indexOf(callback) === -<span class="number">1</span></span><br><span class="line">        : existing !== callback</span><br><span class="line">    ) &#123;</span><br><span class="line">      on[event] = [callback].concat(existing)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    on[event] = callback</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<ul>
<li>原生的 <code>v-model</code>，会根据标签的不同生成不同的事件和属性</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> VueTemplateCompiler = <span class="built_in">require</span>(<span class="string">&#x27;vue-template-compiler&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> ele = VueTemplateCompiler.compile(<span class="string">&#x27;&lt;input v-model=&quot;value&quot;/&gt;&#x27;</span>);</span><br><span class="line"><span class="comment">/** </span></span><br><span class="line"><span class="comment">with(this) &#123;</span></span><br><span class="line"><span class="comment">    return _c(&#x27;input&#x27;, &#123;</span></span><br><span class="line"><span class="comment">        directives: [&#123;</span></span><br><span class="line"><span class="comment">            name: &quot;model&quot;,</span></span><br><span class="line"><span class="comment">            rawName: &quot;v-model&quot;,</span></span><br><span class="line"><span class="comment">            value: (value),</span></span><br><span class="line"><span class="comment">            expression: &quot;value&quot;</span></span><br><span class="line"><span class="comment">        &#125;],</span></span><br><span class="line"><span class="comment">        domProps: &#123;</span></span><br><span class="line"><span class="comment">            &quot;value&quot;: (value)</span></span><br><span class="line"><span class="comment">        &#125;,</span></span><br><span class="line"><span class="comment">        on: &#123;</span></span><br><span class="line"><span class="comment">            &quot;input&quot;: function ($event) &#123;</span></span><br><span class="line"><span class="comment">                if ($event.target.composing) return;</span></span><br><span class="line"><span class="comment">                value = $event.target.value</span></span><br><span class="line"><span class="comment">            &#125;</span></span><br><span class="line"><span class="comment">        &#125;</span></span><br><span class="line"><span class="comment">    &#125;)</span></span><br><span class="line"><span class="comment">&#125;</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>

<blockquote>
<p>编译时：不同的标签解析出的内容不一样 <code>platforms/web/compiler/directives/model.js</code></p>
</blockquote>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (el.component) &#123;</span><br><span class="line">    genComponentModel(el, value, modifiers)</span><br><span class="line">    <span class="comment">// component v-model doesn&#x27;t need extra runtime</span></span><br><span class="line">    <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line">  &#125; <span class="keyword">else</span> <span class="keyword">if</span> (tag === <span class="string">&#x27;select&#x27;</span>) &#123;</span><br><span class="line">    genSelect(el, value, modifiers)</span><br><span class="line">  &#125; <span class="keyword">else</span> <span class="keyword">if</span> (tag === <span class="string">&#x27;input&#x27;</span> &amp;&amp; type === <span class="string">&#x27;checkbox&#x27;</span>) &#123;</span><br><span class="line">    genCheckboxModel(el, value, modifiers)</span><br><span class="line">  &#125; <span class="keyword">else</span> <span class="keyword">if</span> (tag === <span class="string">&#x27;input&#x27;</span> &amp;&amp; type === <span class="string">&#x27;radio&#x27;</span>) &#123;</span><br><span class="line">    genRadioModel(el, value, modifiers)</span><br><span class="line">  &#125; <span class="keyword">else</span> <span class="keyword">if</span> (tag === <span class="string">&#x27;input&#x27;</span> || tag === <span class="string">&#x27;textarea&#x27;</span>) &#123;</span><br><span class="line">    genDefaultModel(el, value, modifiers)</span><br><span class="line">  &#125; <span class="keyword">else</span> <span class="keyword">if</span> (!config.isReservedTag(tag)) &#123;</span><br><span class="line">    genComponentModel(el, value, modifiers)</span><br><span class="line">    <span class="comment">// component v-model doesn&#x27;t need extra runtime</span></span><br><span class="line">    <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>运行时：会对元素处理一些关于输入法的问题 <code>platforms/web/runtime/directives/model.js</code></p>
</blockquote>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">inserted (el, binding, vnode, oldVnode) &#123;</span><br><span class="line">    <span class="keyword">if</span> (vnode.tag === <span class="string">&#x27;select&#x27;</span>) &#123;</span><br><span class="line">      <span class="comment">// #6903</span></span><br><span class="line">      <span class="keyword">if</span> (oldVnode.elm &amp;&amp; !oldVnode.elm._vOptions) &#123;</span><br><span class="line">        mergeVNodeHook(vnode, <span class="string">&#x27;postpatch&#x27;</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">          directive.componentUpdated(el, binding, vnode)</span><br><span class="line">        &#125;)</span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        setSelected(el, binding, vnode.context)</span><br><span class="line">      &#125;</span><br><span class="line">      el._vOptions = [].map.call(el.options, getValue)</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (vnode.tag === <span class="string">&#x27;textarea&#x27;</span> || isTextInputType(el.type)) &#123;</span><br><span class="line">      el._vModifiers = binding.modifiers</span><br><span class="line">      <span class="keyword">if</span> (!binding.modifiers.lazy) &#123;</span><br><span class="line">        el.addEventListener(<span class="string">&#x27;compositionstart&#x27;</span>, onCompositionStart)</span><br><span class="line">        el.addEventListener(<span class="string">&#x27;compositionend&#x27;</span>, onCompositionEnd)</span><br><span class="line">        <span class="comment">// Safari &lt; 10.2 &amp; UIWebView doesn&#x27;t fire compositionend when</span></span><br><span class="line">        <span class="comment">// switching focus before confirming composition choice</span></span><br><span class="line">        <span class="comment">// this also fixes the issue where some browsers e.g. iOS Chrome</span></span><br><span class="line">        <span class="comment">// fires &quot;change&quot; instead of &quot;input&quot; on autocomplete.</span></span><br><span class="line">        el.addEventListener(<span class="string">&#x27;change&#x27;</span>, onCompositionEnd)</span><br><span class="line">        <span class="comment">/* istanbul ignore if */</span></span><br><span class="line">        <span class="keyword">if</span> (isIE9) &#123;</span><br><span class="line">          el.vmodel = <span class="literal">true</span></span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure>

<h2 id="Vue中v-html会导致哪些问题"><a href="#Vue中v-html会导致哪些问题" class="headerlink" title="Vue中v-html会导致哪些问题?"></a><code>Vue</code>中<code>v-html</code>会导致哪些问题?</h2><h3 id="理解-15"><a href="#理解-15" class="headerlink" title="理解"></a>理解</h3><ul>
<li>可能会导致<code>xss</code>攻击</li>
<li><code>v-html</code>会替换掉标签内部的子元素</li>
</ul>
<h3 id="原理-12"><a href="#原理-12" class="headerlink" title="原理"></a>原理</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> template = <span class="built_in">require</span>(<span class="string">&#x27;vue-template-compiler&#x27;</span>);</span><br><span class="line"><span class="keyword">let</span> r = template.compile(<span class="string">`&lt;div v-html=&quot;&#x27;&lt;span&gt;hello&lt;/span&gt;&#x27;&quot;&gt;&lt;/div&gt;`</span>)</span><br><span class="line"><span class="comment">// with(this)&#123;return _c(&#x27;div&#x27;,&#123;domProps:&#123;&quot;innerHTML&quot;:_s(&#x27;&lt;span&gt;hello&lt;/span&gt;&#x27;)&#125;&#125;)&#125;</span></span><br><span class="line"><span class="built_in">console</span>.log(r.render);</span><br><span class="line"></span><br><span class="line"><span class="comment">// _c 定义在core/instance/render.js</span></span><br><span class="line"><span class="comment">// _s 定义在core/instance/render-helpers/index,js</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (key === <span class="string">&#x27;textContent&#x27;</span> || key === <span class="string">&#x27;innerHTML&#x27;</span>) &#123;</span><br><span class="line">      <span class="keyword">if</span> (vnode.children) vnode.children.length = <span class="number">0</span></span><br><span class="line">      <span class="keyword">if</span> (cur === oldProps[key]) <span class="keyword">continue</span></span><br><span class="line">      <span class="comment">// #6601 work around Chrome version &lt;= 55 bug where single textNode</span></span><br><span class="line">      <span class="comment">// replaced by innerHTML/textContent retains its parentNode property</span></span><br><span class="line">      <span class="keyword">if</span> (elm.childNodes.length === <span class="number">1</span>) &#123;</span><br><span class="line">        elm.removeChild(elm.childNodes[<span class="number">0</span>])</span><br><span class="line">      &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="Vue父子组件生命周期调用顺序"><a href="#Vue父子组件生命周期调用顺序" class="headerlink" title="Vue父子组件生命周期调用顺序"></a><code>Vue</code>父子组件生命周期调用顺序</h2><h3 id="理解-16"><a href="#理解-16" class="headerlink" title="理解"></a>理解</h3><p>组件的调用顺序都是先父后子,渲染完成的顺序肯定是先子后父</p>
<p>组件的销毁操作是先父后子，销毁完成的顺序是先子后父</p>
<h3 id="原理-13"><a href="#原理-13" class="headerlink" title="原理"></a>原理</h3><p><img src="/2020/10/21/vue%E7%AC%94%E8%AE%B0/vue-souce/%E7%BB%84%E4%BB%B6%E7%9A%84%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F-1582263422513.png"></p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">patch</span> (<span class="params">oldVnode, vnode, hydrating, removeOnly</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (isUndef(vnode)) &#123;</span><br><span class="line">      <span class="keyword">if</span> (isDef(oldVnode)) invokeDestroyHook(oldVnode)</span><br><span class="line">      <span class="keyword">return</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> isInitialPatch = <span class="literal">false</span></span><br><span class="line">    <span class="keyword">const</span> insertedVnodeQueue = [] <span class="comment">// 定义收集所有组件的insert hook方法的数组</span></span><br><span class="line">    <span class="comment">// somthing ...</span></span><br><span class="line">    createElm(</span><br><span class="line">        vnode,</span><br><span class="line">        insertedVnodeQueue,</span><br><span class="line">        oldElm._leaveCb ? <span class="literal">null</span> : parentElm,</span><br><span class="line">        nodeOps.nextSibling(oldElm)</span><br><span class="line">    )</span><br><span class="line"> <span class="comment">// somthing...</span></span><br><span class="line">    <span class="comment">// 最终会依次调用收集的insert hook</span></span><br><span class="line">    invokeInsertHook(vnode, insertedVnodeQueue, isInitialPatch);</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> vnode.elm</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">createElm</span> (<span class="params"></span></span></span><br><span class="line"><span class="function"><span class="params">    vnode,</span></span></span><br><span class="line"><span class="function"><span class="params">    insertedVnodeQueue,</span></span></span><br><span class="line"><span class="function"><span class="params">    parentElm,</span></span></span><br><span class="line"><span class="function"><span class="params">    refElm,</span></span></span><br><span class="line"><span class="function"><span class="params">    nested,</span></span></span><br><span class="line"><span class="function"><span class="params">    ownerArray,</span></span></span><br><span class="line"><span class="function"><span class="params">    index</span></span></span><br><span class="line"><span class="function"><span class="params">  </span>) </span>&#123;</span><br><span class="line">        <span class="comment">// createChildren会递归创建儿子组件</span></span><br><span class="line">        createChildren(vnode, children, insertedVnodeQueue) </span><br><span class="line">        <span class="comment">// something...</span></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 将组件的vnode插入到数组中</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">invokeCreateHooks</span> (<span class="params">vnode, insertedVnodeQueue</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; cbs.create.length; ++i) &#123;</span><br><span class="line">      cbs.create[i](emptyNode, vnode)</span><br><span class="line">    &#125;</span><br><span class="line">    i = vnode.data.hook <span class="comment">// Reuse variable</span></span><br><span class="line">    <span class="keyword">if</span> (isDef(i)) &#123;</span><br><span class="line">      <span class="keyword">if</span> (isDef(i.create)) i.create(emptyNode, vnode)</span><br><span class="line">      <span class="keyword">if</span> (isDef(i.insert)) insertedVnodeQueue.push(vnode)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"><span class="comment">// insert方法中会依次调用mounted方法</span></span><br><span class="line">insert (vnode: MountedComponentVNode) &#123;</span><br><span class="line">    <span class="keyword">const</span> &#123; context, componentInstance &#125; = vnode</span><br><span class="line">    <span class="keyword">if</span> (!componentInstance._isMounted) &#123;</span><br><span class="line">      componentInstance._isMounted = <span class="literal">true</span></span><br><span class="line">      callHook(componentInstance, <span class="string">&#x27;mounted&#x27;</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">invokeInsertHook</span> (<span class="params">vnode, queue, initial</span>) </span>&#123;</span><br><span class="line">     <span class="comment">// delay insert hooks for component root nodes, invoke them after the</span></span><br><span class="line">     <span class="comment">// element is really inserted</span></span><br><span class="line">     <span class="keyword">if</span> (isTrue(initial) &amp;&amp; isDef(vnode.parent)) &#123;</span><br><span class="line">         vnode.parent.data.pendingInsert = queue</span><br><span class="line">     &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">         <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; queue.length; ++i) &#123;</span><br><span class="line">             queue[i].data.hook.insert(queue[i]); <span class="comment">// 调用insert方法</span></span><br><span class="line">         &#125;</span><br><span class="line">     &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">Vue.prototype.$destroy = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">    callHook(vm, <span class="string">&#x27;beforeDestroy&#x27;</span>) <span class="comment">// </span></span><br><span class="line">    <span class="comment">// invoke destroy hooks on current rendered tree</span></span><br><span class="line">    vm.__patch__(vm._vnode, <span class="literal">null</span>) <span class="comment">// 先销毁儿子 </span></span><br><span class="line">    <span class="comment">// fire destroyed hook</span></span><br><span class="line">    callHook(vm, <span class="string">&#x27;destroyed&#x27;</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="Vue组件如何通信"><a href="#Vue组件如何通信" class="headerlink" title="Vue组件如何通信?"></a><code>Vue</code>组件如何通信?</h2><ul>
<li>父子间通信  父-&gt;子通过<code>props</code>、子-&gt; 父<code>$on、$emit</code></li>
<li>获取父子组件实例的方式<code>$parent、$children</code></li>
<li>在父组件中提供数据子组件进行消费 <code>Provide、inject</code></li>
<li><code>Ref</code>获取实例的方式调用组件的属性或者方法</li>
<li><code>Event Bus</code> 实现跨组件通信</li>
<li><code>Vuex</code>状态管理实现通信</li>
</ul>
<h2 id="Vue中相同逻辑如何抽离？"><a href="#Vue中相同逻辑如何抽离？" class="headerlink" title="Vue中相同逻辑如何抽离？"></a><code>Vue</code>中相同逻辑如何抽离？</h2><ul>
<li><code>Vue.mixin</code>用法 给组件每个生命周期，函数等都混入一些公共逻辑</li>
</ul>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line">Vue.mixin = <span class="function"><span class="keyword">function</span> (<span class="params">mixin: <span class="built_in">Object</span></span>) </span>&#123;</span><br><span class="line">    <span class="built_in">this</span>.options = mergeOptions(<span class="built_in">this</span>.options, mixin); <span class="comment">// 将当前定义的属性合并到每个组件中</span></span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">this</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">mergeOptions</span> (<span class="params"></span></span></span><br><span class="line"><span class="function"><span class="params">  parent: <span class="built_in">Object</span>,</span></span></span><br><span class="line"><span class="function"><span class="params">  child: <span class="built_in">Object</span>,</span></span></span><br><span class="line"><span class="function"><span class="params">  vm?: Component</span></span></span><br><span class="line"><span class="function"><span class="params"></span>): <span class="title">Object</span> </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (!child._base) &#123;</span><br><span class="line">    <span class="keyword">if</span> (child.extends) &#123; <span class="comment">// 递归合并extends</span></span><br><span class="line">      parent = mergeOptions(parent, child.extends, vm)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (child.mixins) &#123; <span class="comment">// 递归合并mixin</span></span><br><span class="line">      <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>, l = child.mixins.length; i &lt; l; i++) &#123;</span><br><span class="line">        parent = mergeOptions(parent, child.mixins[i], vm)</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">const</span> options = &#123;&#125; <span class="comment">// 属性及生命周期的合并</span></span><br><span class="line">  <span class="keyword">let</span> key</span><br><span class="line">  <span class="keyword">for</span> (key <span class="keyword">in</span> parent) &#123;</span><br><span class="line">    mergeField(key)</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">for</span> (key <span class="keyword">in</span> child) &#123;</span><br><span class="line">    <span class="keyword">if</span> (!hasOwn(parent, key)) &#123;</span><br><span class="line">      mergeField(key)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="function"><span class="keyword">function</span> <span class="title">mergeField</span> (<span class="params">key</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">const</span> strat = strats[key] || defaultStrat</span><br><span class="line">    <span class="comment">// 调用不同属性合并策略进行合并</span></span><br><span class="line">    options[key] = strat(parent[key], child[key], vm, key)</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> options</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="为什么要使用异步组件？"><a href="#为什么要使用异步组件？" class="headerlink" title="为什么要使用异步组件？"></a>为什么要使用异步组件？</h2><h3 id="理解-17"><a href="#理解-17" class="headerlink" title="理解"></a>理解</h3><ul>
<li><p>如果组件功能多打包出的结果会变大，我可以采用异步的方式来加载组件。主要依赖<code>import()</code>这个语法，可以实现文件的分割加载。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">components:&#123;</span><br><span class="line"> <span class="function"><span class="title">AddCustomerSchedule</span>(<span class="params">resolve</span>)</span> &#123;</span><br><span class="line">        <span class="built_in">require</span>([<span class="string">&quot;../components/AddCustomer&quot;</span>], resolve);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

</li>
</ul>
<h3 id="原理-14"><a href="#原理-14" class="headerlink" title="原理"></a>原理</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">createComponent</span> (<span class="params"></span></span></span><br><span class="line"><span class="function"><span class="params">  Ctor: Class&lt;Component&gt; | <span class="built_in">Function</span> | <span class="built_in">Object</span> | <span class="keyword">void</span>,</span></span></span><br><span class="line"><span class="function"><span class="params">  data: ?VNodeData,</span></span></span><br><span class="line"><span class="function"><span class="params">  context: Component,</span></span></span><br><span class="line"><span class="function"><span class="params">  children: ?<span class="built_in">Array</span>&lt;VNode&gt;,</span></span></span><br><span class="line"><span class="function"><span class="params">  tag?: string</span></span></span><br><span class="line"><span class="function"><span class="params"></span>): <span class="title">VNode</span> | <span class="title">Array</span>&lt;<span class="title">VNode</span>&gt; | <span class="title">void</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// async component</span></span><br><span class="line">  <span class="keyword">let</span> asyncFactory</span><br><span class="line">  <span class="keyword">if</span> (isUndef(Ctor.cid)) &#123;</span><br><span class="line">    asyncFactory = Ctor</span><br><span class="line">    Ctor = resolveAsyncComponent(asyncFactory, baseCtor) <span class="comment">// 默认调用此函数时返回undefiend</span></span><br><span class="line">    <span class="comment">// 第二次渲染时Ctor不为undefined</span></span><br><span class="line">    <span class="keyword">if</span> (Ctor === <span class="literal">undefined</span>) &#123;</span><br><span class="line">      <span class="keyword">return</span> createAsyncPlaceholder( <span class="comment">// 渲染占位符 空虚拟节点</span></span><br><span class="line">        asyncFactory,</span><br><span class="line">        data,</span><br><span class="line">        context,</span><br><span class="line">        children,</span><br><span class="line">        tag</span><br><span class="line">      )</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">resolveAsyncComponent</span> (<span class="params"></span></span></span><br><span class="line"><span class="function"><span class="params">  factory: <span class="built_in">Function</span>,</span></span></span><br><span class="line"><span class="function"><span class="params">  baseCtor: Class&lt;Component&gt;</span></span></span><br><span class="line"><span class="function"><span class="params"></span>): <span class="title">Class</span>&lt;<span class="title">Component</span>&gt; | <span class="title">void</span> </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (isDef(factory.resolved)) &#123; <span class="comment">// 在次渲染时可以拿到获取的最新组件</span></span><br><span class="line">    <span class="keyword">return</span> factory.resolved</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">const</span> resolve = once(<span class="function">(<span class="params">res: <span class="built_in">Object</span> | Class&lt;Component&gt;</span>) =&gt;</span> &#123;</span><br><span class="line">      factory.resolved = ensureCtor(res, baseCtor)</span><br><span class="line">      <span class="keyword">if</span> (!sync) &#123;</span><br><span class="line">        forceRender(<span class="literal">true</span>) <span class="comment">// 强制更新视图重新渲染</span></span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        owners.length = <span class="number">0</span></span><br><span class="line">      &#125;</span><br><span class="line">  &#125;)</span><br><span class="line">  <span class="keyword">const</span> reject = once(<span class="function"><span class="params">reason</span> =&gt;</span> &#123;</span><br><span class="line">      <span class="keyword">if</span> (isDef(factory.errorComp)) &#123;</span><br><span class="line">          factory.error = <span class="literal">true</span></span><br><span class="line">          forceRender(<span class="literal">true</span>)</span><br><span class="line">      &#125;</span><br><span class="line">  &#125;)</span><br><span class="line">  <span class="keyword">const</span> res = factory(resolve, reject)<span class="comment">// 将resolve方法和reject方法传入，用户调用resolve方法后</span></span><br><span class="line">  sync = <span class="literal">false</span></span><br><span class="line">  <span class="keyword">return</span> factory.resolved</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="什么是作用域插槽"><a href="#什么是作用域插槽" class="headerlink" title="什么是作用域插槽?"></a>什么是作用域插槽?</h2><h3 id="理解-18"><a href="#理解-18" class="headerlink" title="理解"></a>理解</h3><h4 id="插槽"><a href="#插槽" class="headerlink" title="插槽"></a>插槽</h4><ul>
<li>创建组件虚拟节点时，会将组件的儿子的虚拟节点保存起来。当初始化组件时,通过插槽属性将儿子进行分类 <code>&#123;a:[vnode],b[vnode]&#125;</code></li>
<li>渲染组件时会拿对应的slot属性的节点进行替换操作。（插槽的作用域为父组件）</li>
</ul>
<h4 id="作用域插槽"><a href="#作用域插槽" class="headerlink" title="作用域插槽"></a>作用域插槽</h4><ul>
<li>作用域插槽在解析的时候，不会作为组件的孩子节点。会解析成函数，当子组件渲染时，会调用此函数进行渲染。（插槽的作用域为子组件）</li>
</ul>
<h3 id="原理-15"><a href="#原理-15" class="headerlink" title="原理"></a>原理</h3><p><img src="/2020/10/21/vue%E7%AC%94%E8%AE%B0/vue-souce/%E6%8F%92%E6%A7%BD.png"></p>
<h4 id="插槽-1"><a href="#插槽-1" class="headerlink" title="插槽"></a>插槽</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> VueTemplateCompiler = <span class="built_in">require</span>(<span class="string">&#x27;vue-template-compiler&#x27;</span>);</span><br><span class="line"><span class="keyword">let</span> ele = VueTemplateCompiler.compile(<span class="string">`</span></span><br><span class="line"><span class="string">    &lt;my-component&gt;</span></span><br><span class="line"><span class="string">        &lt;div slot=&quot;header&quot;&gt;node&lt;/div&gt;</span></span><br><span class="line"><span class="string">        &lt;div&gt;react&lt;/div&gt;</span></span><br><span class="line"><span class="string">        &lt;div slot=&quot;footer&quot;&gt;vue&lt;/div&gt;</span></span><br><span class="line"><span class="string">    &lt;/my-component&gt;</span></span><br><span class="line"><span class="string">`</span>)</span><br><span class="line"><span class="comment">/** </span></span><br><span class="line"><span class="comment">with(this) &#123;</span></span><br><span class="line"><span class="comment">    return _c(&#x27;my-component&#x27;, [_c(&#x27;div&#x27;, &#123;</span></span><br><span class="line"><span class="comment">        attrs: &#123;</span></span><br><span class="line"><span class="comment">            &quot;slot&quot;: &quot;header&quot;</span></span><br><span class="line"><span class="comment">        &#125;,</span></span><br><span class="line"><span class="comment">        slot: &quot;header&quot;</span></span><br><span class="line"><span class="comment">    &#125;, [_v(&quot;node&quot;)]), _v(&quot; &quot;), _c(&#x27;div&#x27;, [_v(&quot;react&quot;)]), _v(&quot; &quot;), _c(&#x27;div&#x27;, &#123;</span></span><br><span class="line"><span class="comment">        attrs: &#123;</span></span><br><span class="line"><span class="comment">            &quot;slot&quot;: &quot;footer&quot;</span></span><br><span class="line"><span class="comment">        &#125;,</span></span><br><span class="line"><span class="comment">        slot: &quot;footer&quot;</span></span><br><span class="line"><span class="comment">    &#125;, [_v(&quot;vue&quot;)])])</span></span><br><span class="line"><span class="comment">&#125;</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> VueTemplateCompiler = <span class="built_in">require</span>(<span class="string">&#x27;vue-template-compiler&#x27;</span>);</span><br><span class="line"><span class="keyword">let</span> ele = VueTemplateCompiler.compile(<span class="string">`</span></span><br><span class="line"><span class="string">    &lt;div&gt;</span></span><br><span class="line"><span class="string">        &lt;slot name=&quot;header&quot;&gt;&lt;/slot&gt;</span></span><br><span class="line"><span class="string">        &lt;slot name=&quot;footer&quot;&gt;&lt;/slot&gt;</span></span><br><span class="line"><span class="string">        &lt;slot&gt;&lt;/slot&gt;</span></span><br><span class="line"><span class="string">    &lt;/div&gt;</span></span><br><span class="line"><span class="string">`</span>);</span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">with(this) &#123;</span></span><br><span class="line"><span class="comment">    return _c(&#x27;div&#x27;, [_t(&quot;header&quot;), _v(&quot; &quot;), _t(&quot;footer&quot;), _v(&quot; &quot;), _t(&quot;default&quot;)], 2)</span></span><br><span class="line"><span class="comment">&#125;</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="comment">// _t定义在 core/instance/render-helpers/index.js</span></span><br></pre></td></tr></table></figure>

<h3 id="作用域插槽-1"><a href="#作用域插槽-1" class="headerlink" title="作用域插槽"></a>作用域插槽</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">let</span> ele = VueTemplateCompiler.compile(<span class="string">`</span></span><br><span class="line"><span class="string">    &lt;app&gt;</span></span><br><span class="line"><span class="string">        &lt;div slot-scope=&quot;msg&quot; slot=&quot;footer&quot;&gt;&#123;&#123;msg.a&#125;&#125;&lt;/div&gt;</span></span><br><span class="line"><span class="string">    &lt;/app&gt;</span></span><br><span class="line"><span class="string">`</span>);</span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">with(this) &#123;</span></span><br><span class="line"><span class="comment">    return _c(&#x27;app&#x27;, &#123;</span></span><br><span class="line"><span class="comment">        scopedSlots: _u([&#123; // 作用域插槽的内容会被渲染成一个函数</span></span><br><span class="line"><span class="comment">            key: &quot;footer&quot;,</span></span><br><span class="line"><span class="comment">            fn: function (msg) &#123;</span></span><br><span class="line"><span class="comment">                return _c(&#x27;div&#x27;, &#123;&#125;, [_v(_s(msg.a))])</span></span><br><span class="line"><span class="comment">            &#125;</span></span><br><span class="line"><span class="comment">        &#125;])</span></span><br><span class="line"><span class="comment">    &#125;)</span></span><br><span class="line"><span class="comment"> &#125;</span></span><br><span class="line"><span class="comment">&#125;</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="keyword">const</span> VueTemplateCompiler = <span class="built_in">require</span>(<span class="string">&#x27;vue-template-compiler&#x27;</span>);</span><br><span class="line"></span><br><span class="line">VueTemplateCompiler.compile(<span class="string">`</span></span><br><span class="line"><span class="string">    &lt;div&gt;</span></span><br><span class="line"><span class="string">        &lt;slot name=&quot;footer&quot; a=&quot;1&quot; b=&quot;2&quot;&gt;&lt;/slot&gt;</span></span><br><span class="line"><span class="string">    &lt;/div&gt;</span></span><br><span class="line"><span class="string">`</span>);</span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">with(this) &#123;</span></span><br><span class="line"><span class="comment">    return _c(&#x27;div&#x27;, [_t(&quot;footer&quot;, null, &#123;</span></span><br><span class="line"><span class="comment">        &quot;a&quot;: &quot;1&quot;,</span></span><br><span class="line"><span class="comment">        &quot;b&quot;: &quot;2&quot;</span></span><br><span class="line"><span class="comment">    &#125;)], 2)</span></span><br><span class="line"><span class="comment">&#125;</span></span><br><span class="line"><span class="comment">**/</span></span><br></pre></td></tr></table></figure>

<h2 id="谈谈你对-keep-alive-的了解？"><a href="#谈谈你对-keep-alive-的了解？" class="headerlink" title="谈谈你对 keep-alive 的了解？"></a>谈谈你对 keep-alive 的了解？</h2><h3 id="理解-19"><a href="#理解-19" class="headerlink" title="理解"></a>理解</h3><p><code>keep-alive</code>可以实现组件的缓存，当组件切换时不会对当前组件进行卸载,常用的2个属性<code>include</code>/<code>exclude</code>,2个生命周期<code>activated</code>,<code>deactivated</code></p>
<h3 id="原理-16"><a href="#原理-16" class="headerlink" title="原理"></a>原理</h3><blockquote>
<p><code>core/components/keep-alive.js</code></p>
</blockquote>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  name: <span class="string">&#x27;keep-alive&#x27;</span>,</span><br><span class="line">  abstract: <span class="literal">true</span>, <span class="comment">// 抽象组件</span></span><br><span class="line"></span><br><span class="line">  props: &#123;</span><br><span class="line">    include: patternTypes,</span><br><span class="line">    exclude: patternTypes,</span><br><span class="line">    max: [<span class="built_in">String</span>, <span class="built_in">Number</span>]</span><br><span class="line">  &#125;,</span><br><span class="line"></span><br><span class="line">  created () &#123;</span><br><span class="line">    <span class="built_in">this</span>.cache = <span class="built_in">Object</span>.create(<span class="literal">null</span>) <span class="comment">// 创建缓存列表</span></span><br><span class="line">    <span class="built_in">this</span>.keys = [] <span class="comment">// 创建缓存组件的key列表</span></span><br><span class="line">  &#125;,</span><br><span class="line"></span><br><span class="line">  destroyed () &#123; <span class="comment">// keep-alive销毁时 会清空所有的缓存和key</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">const</span> key <span class="keyword">in</span> <span class="built_in">this</span>.cache) &#123; <span class="comment">// 循环销毁</span></span><br><span class="line">      pruneCacheEntry(<span class="built_in">this</span>.cache, key, <span class="built_in">this</span>.keys)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line"></span><br><span class="line">  mounted () &#123; <span class="comment">// 会监控include 和 include属性 进行组件的缓存处理</span></span><br><span class="line">    <span class="built_in">this</span>.$watch(<span class="string">&#x27;include&#x27;</span>, <span class="function"><span class="params">val</span> =&gt;</span> &#123;</span><br><span class="line">      pruneCache(<span class="built_in">this</span>, <span class="function"><span class="params">name</span> =&gt;</span> matches(val, name))</span><br><span class="line">    &#125;)</span><br><span class="line">    <span class="built_in">this</span>.$watch(<span class="string">&#x27;exclude&#x27;</span>, <span class="function"><span class="params">val</span> =&gt;</span> &#123;</span><br><span class="line">      pruneCache(<span class="built_in">this</span>, <span class="function"><span class="params">name</span> =&gt;</span> !matches(val, name))</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;,</span><br><span class="line"></span><br><span class="line">  render () &#123;</span><br><span class="line">    <span class="keyword">const</span> slot = <span class="built_in">this</span>.$slots.default <span class="comment">// 会默认拿插槽</span></span><br><span class="line">    <span class="keyword">const</span> vnode: VNode = getFirstComponentChild(slot) <span class="comment">// 只缓存第一个组件</span></span><br><span class="line">    <span class="keyword">const</span> componentOptions: ?VNodeComponentOptions = vnode &amp;&amp; vnode.componentOptions</span><br><span class="line">    <span class="keyword">if</span> (componentOptions) &#123;</span><br><span class="line">      <span class="comment">// check pattern</span></span><br><span class="line">      <span class="keyword">const</span> name: ?string = getComponentName(componentOptions) <span class="comment">// 取出组件的名字</span></span><br><span class="line">      <span class="keyword">const</span> &#123; include, exclude &#125; = <span class="built_in">this</span></span><br><span class="line">      <span class="keyword">if</span> ( <span class="comment">// 判断是否缓存</span></span><br><span class="line">        <span class="comment">// not included</span></span><br><span class="line">        (include &amp;&amp; (!name || !matches(include, name))) ||</span><br><span class="line">        <span class="comment">// excluded</span></span><br><span class="line">        (exclude &amp;&amp; name &amp;&amp; matches(exclude, name))</span><br><span class="line">      ) &#123;</span><br><span class="line">        <span class="keyword">return</span> vnode</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">const</span> &#123; cache, keys &#125; = <span class="built_in">this</span></span><br><span class="line">      <span class="keyword">const</span> key: ?string = vnode.key == <span class="literal">null</span></span><br><span class="line">        <span class="comment">// same constructor may get registered as different local components</span></span><br><span class="line">        <span class="comment">// so cid alone is not enough (#3269)</span></span><br><span class="line">        ? componentOptions.Ctor.cid + (componentOptions.tag ? <span class="string">`::<span class="subst">$&#123;componentOptions.tag&#125;</span>`</span> : <span class="string">&#x27;&#x27;</span>)</span><br><span class="line">        : vnode.key <span class="comment">// 如果组件没key 就自己通过 组件的标签和key和cid 拼接一个key</span></span><br><span class="line"></span><br><span class="line">      <span class="keyword">if</span> (cache[key]) &#123;</span><br><span class="line">        vnode.componentInstance = cache[key].componentInstance <span class="comment">//  直接拿到组件实例</span></span><br><span class="line">        <span class="comment">// make current key freshest</span></span><br><span class="line">        remove(keys, key) <span class="comment">// 删除当前的  [b,c,d,e,a]   // LRU 最近最久未使用法</span></span><br><span class="line">        keys.push(key) <span class="comment">// 并将key放到后面[b,a]</span></span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        cache[key] = vnode <span class="comment">// 缓存vnode</span></span><br><span class="line">        keys.push(key) <span class="comment">// 将key 存入</span></span><br><span class="line">        <span class="comment">// prune oldest entry</span></span><br><span class="line">        <span class="keyword">if</span> (<span class="built_in">this</span>.max &amp;&amp; keys.length &gt; <span class="built_in">parseInt</span>(<span class="built_in">this</span>.max)) &#123; <span class="comment">// 缓存的太多超过了max 就需要删除掉</span></span><br><span class="line">          pruneCacheEntry(cache, keys[<span class="number">0</span>], keys, <span class="built_in">this</span>._vnode) <span class="comment">// 要删除第0个 但是现在渲染的就是第0个</span></span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      vnode.data.keepAlive = <span class="literal">true</span> <span class="comment">// 并且标准keep-alive下的组件是一个缓存组件</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> vnode || (slot &amp;&amp; slot[<span class="number">0</span>]) <span class="comment">// 返回当前的虚拟节点</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="Vue中常见性能优化"><a href="#Vue中常见性能优化" class="headerlink" title="Vue中常见性能优化"></a><code>Vue</code>中常见性能优化</h2><h3 id="编码优化"><a href="#编码优化" class="headerlink" title="编码优化"></a>编码优化</h3><ul>
<li><p>不要将所有的数据都放在data中，data中的数据都会增加getter和setter，会收集对应的watcher</p>
</li>
<li><p><code>vue</code> 在 v-for 时给每项元素绑定事件需要用事件代理</p>
</li>
<li><p><code>SPA</code>页面采用keep-alive缓存组件</p>
</li>
<li><p>拆分组件( 提高复用性、增加代码的可维护性,减少不必要的渲染  )</p>
</li>
<li><p><code>v-if</code> 当值为false时内部指令不会执行,具有阻断功能，很多情况下使用v-if替代v-show</p>
</li>
<li><p><code>key</code>保证唯一性 ( 默认<code>vue</code>会采用就地复用策略 )</p>
</li>
<li><p><code>Object.freeze</code> 冻结数据</p>
</li>
<li><p>合理使用路由懒加载、异步组件</p>
</li>
<li><p>尽量采用runtime运行时版本</p>
</li>
<li><p>数据持久化的问题 （防抖、节流）</p>
</li>
</ul>
<h3 id="Vue加载性能优化"><a href="#Vue加载性能优化" class="headerlink" title="Vue加载性能优化"></a><code>Vue</code>加载性能优化</h3><ul>
<li><p>第三方模块按需导入 (<code>babel-plugin-component</code>)</p>
</li>
<li><p>滚动到可视区域动态加载  ( <a target="_blank" rel="noopener" href="https://tangbc.github.io/vue-virtual-scroll-list">https://tangbc.github.io/vue-virtual-scroll-list</a> )</p>
</li>
<li><p>图片懒加载  (<a target="_blank" rel="noopener" href="https://github.com/hilongjw/vue-lazyload.git">https://github.com/hilongjw/vue-lazyload.git</a>)</p>
</li>
</ul>
<h3 id="用户体验"><a href="#用户体验" class="headerlink" title="用户体验"></a>用户体验</h3><ul>
<li><code>app-skeleton</code>骨架屏</li>
<li><code>app-shell</code>app壳</li>
<li><code>pwa</code></li>
</ul>
<h3 id="SEO优化"><a href="#SEO优化" class="headerlink" title="SEO优化"></a><code>SEO</code>优化</h3><ul>
<li>预渲染插件 <code>prerender-spa-plugin</code></li>
<li>服务端渲染<code>ssr</code></li>
</ul>
<h3 id="打包优化"><a href="#打包优化" class="headerlink" title="打包优化"></a>打包优化</h3><ul>
<li>使用<code>cdn</code>的方式加载第三方模块</li>
<li>多线程打包 <code>happypack</code></li>
<li><code>splitChunks</code> 抽离公共文件</li>
<li><code>sourceMap</code>生成</li>
</ul>
<h3 id="缓存，压缩"><a href="#缓存，压缩" class="headerlink" title="缓存，压缩"></a>缓存，压缩</h3><ul>
<li>客户端缓存、服务端缓存</li>
<li>服务端<code>gzip</code>压缩</li>
</ul>
<h2 id="Vue3-0你知道有哪些改进"><a href="#Vue3-0你知道有哪些改进" class="headerlink" title="Vue3.0你知道有哪些改进?"></a><code>Vue3.0</code>你知道有哪些改进?</h2><ul>
<li><p><code>Vue3</code>采用了TS来编写</p>
</li>
<li><p>支持 <code>Composition API</code></p>
</li>
<li><p><code>Vue3</code>中响应式数据原理改成<code>proxy</code></p>
</li>
<li><p><code>vdom</code>的对比算法更新，只更新<code>vdom</code>的绑定了动态数据的部分</p>
</li>
</ul>
<h2 id="实现hash路由和history路由"><a href="#实现hash路由和history路由" class="headerlink" title="实现hash路由和history路由"></a>实现<code>hash</code>路由和<code>history</code>路由</h2><ul>
<li><code>onhashchange</code></li>
<li><code>history.pushState</code></li>
</ul>
<h2 id="Vue-Router中导航守卫有哪些？"><a href="#Vue-Router中导航守卫有哪些？" class="headerlink" title="Vue-Router中导航守卫有哪些？"></a><code>Vue-Router</code>中导航守卫有哪些？</h2><h3 id="完整的导航解析流程"><a href="#完整的导航解析流程" class="headerlink" title="完整的导航解析流程"></a>完整的导航解析流程</h3><ul>
<li>导航被触发。</li>
<li>在失活的组件里调用离开守卫 <code>beforeRouteLeave</code>。</li>
<li>调用全局的 <code>beforeEach</code> 守卫。</li>
<li>在重用的组件里调用 <code>beforeRouteUpdate</code> 守卫 (2+)。</li>
<li>在路由配置里调用 <code>beforeEnter</code>。</li>
<li>解析异步路由组件。</li>
<li>在被激活的组件里调用 <code>beforeRouteEnter</code>。</li>
<li>调用全局的 <code>beforeResolve</code> 守卫 (5+)。</li>
<li>导航被确认。</li>
<li>调用全局的 <code>afterEach</code> 钩子。</li>
<li>触发 DOM 更新。</li>
<li>用创建好的实例调用 <code>beforeRouteEnter</code> 守卫中传给 <code>next</code> 的回调函数。</li>
</ul>
<h2 id="action-和-mutation区别"><a href="#action-和-mutation区别" class="headerlink" title="action 和 mutation区别"></a><code>action</code> 和 <code>mutation</code>区别</h2><ul>
<li><code>mutation</code>是同步更新数据(内部会进行是否为异步方式更新数据的检测)</li>
<li><code>action</code> 异步操作，可以获取数据后调佣<code>mutation</code>提交最终数据</li>
</ul>
<h2 id="简述Vuex工作原理"><a href="#简述Vuex工作原理" class="headerlink" title="简述Vuex工作原理"></a>简述<code>Vuex</code>工作原理</h2><p><img src="https://vuex.vuejs.org/vuex.png"></p>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/kity@2.0.4/dist/kity.min.js"></script><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/kityminder-core@1.4.50/dist/kityminder.core.min.js"></script><script defer="true" type="text/javascript" src="https://cdn.jsdelivr.net/npm/hexo-simple-mindmap@0.2.0/dist/mindmap.min.js"></script><link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/hexo-simple-mindmap@0.2.0/dist/mindmap.min.css">
    </div>

    
    
    

    <footer class="post-footer">
          <div class="post-tags">
              <a href="/tags/vue/" rel="tag"># vue</a>
          </div>

        

          <div class="post-nav">
            <div class="post-nav-item">
            </div>
            <div class="post-nav-item">
                <a href="/2020/10/21/react%E7%AC%94%E8%AE%B0/React%E5%9F%BA%E7%A1%80%E7%AF%87/" rel="next" title="react 基础">
                  react 基础 <i class="fa fa-chevron-right"></i>
                </a>
            </div>
          </div>
    </footer>
  </article>
</div>






</div>
  </main>

  <footer class="footer">
    <div class="footer-inner">


<div class="copyright">
  &copy; 
  <span itemprop="copyrightYear">2023</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">郭泽</span>
</div>
  <div class="powered-by">由 <a href="https://hexo.io/" rel="noopener" target="_blank">Hexo</a> & <a href="https://theme-next.js.org/" rel="noopener" target="_blank">NexT.Gemini</a> 强力驱动
  </div>

    </div>
  </footer>

  
  <script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js" integrity="sha256-XL2inqUJaslATFnHdJOi9GfQ60on8Wx1C2H8DYiN1xY=" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/fancybox/3.5.7/jquery.fancybox.min.js" integrity="sha256-yt2kYMy0w8AbtF89WXb2P1rfjcP/HTHLT7097U8Y5b8=" crossorigin="anonymous"></script>
<script src="/js/comments.js"></script><script src="/js/utils.js"></script><script src="/js/motion.js"></script><script src="/js/next-boot.js"></script><script src="/js/bookmark.js"></script>

  
<script src="https://cdnjs.cloudflare.com/ajax/libs/hexo-generator-searchdb/1.4.0/search.js" integrity="sha256-vXZMYLEqsROAXkEw93GGIvaB2ab+QW6w3+1ahD9nXXA=" crossorigin="anonymous"></script>
<script src="/js/third-party/search/local-search.js"></script>

  <script class="next-config" data-name="pdf" type="application/json">{"object_url":{"url":"https://cdnjs.cloudflare.com/ajax/libs/pdfobject/2.2.8/pdfobject.min.js","integrity":"sha256-tu9j5pBilBQrWSDePOOajCUdz6hWsid/lBNzK4KgEPM="},"url":"/lib/pdf/web/viewer.html"}</script>
  <script src="/js/third-party/tags/pdf.js"></script>

  <script class="next-config" data-name="mermaid" type="application/json">{"enable":true,"theme":{"light":"default","dark":"dark"},"js":{"url":"https://cdnjs.cloudflare.com/ajax/libs/mermaid/9.1.3/mermaid.min.js","integrity":"sha256-TIYL00Rhw/8WaoUhYTLX9SKIEFdXxg+yMWSLVUbhiLg="}}</script>
  <script src="/js/third-party/tags/mermaid.js"></script>

  <script src="/js/third-party/fancybox.js"></script>


  





</body>
</html>
